diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index 0f411eda49dbc..ddf52caed088a 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -14,7 +14,6 @@ #![feature(const_fn_transmute)] #![feature(const_panic)] #![feature(crate_visibility_modifier)] -#![feature(iterator_fold_self)] #![feature(label_break_value)] #![feature(nll)] #![feature(or_patterns)] diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 90d31d4801f92..024d9687f3119 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -28,7 +28,7 @@ pub trait ExpectOne { impl ExpectOne for SmallVec { fn expect_one(self, err: &'static str) -> A::Item { - assert!(self.len() == 1, err); + assert!(self.len() == 1, "{}", err); self.into_iter().next().unwrap() } } diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 36d261fb737ce..5880bbd3de44e 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -13,6 +13,7 @@ #![feature(unboxed_closures)] #![feature(generator_trait)] #![feature(fn_traits)] +#![feature(int_bits_const)] #![feature(min_specialization)] #![feature(auto_traits)] #![feature(nll)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0463.md b/compiler/rustc_error_codes/src/error_codes/E0463.md index e46938c607d34..d0cd1b1dcb75b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0463.md +++ b/compiler/rustc_error_codes/src/error_codes/E0463.md @@ -11,3 +11,24 @@ extern crate cake_is_a_lie; // error: can't find crate for `cake_is_a_lie` You need to link your code to the relevant crate in order to be able to use it (through Cargo or the `-L` option of rustc example). Plugins are crates as well, and you link to them the same way. + +## Common causes + +- The crate is not present at all. If using Cargo, add it to `[dependencies]` + in Cargo.toml. +- The crate is present, but under a different name. If using Cargo, look for + `package = ` under `[dependencies]` in Cargo.toml. + +## Common causes for missing `std` or `core` + +- You are cross-compiling for a target which doesn't have `std` prepackaged. + Consider one of the following: + + Adding a pre-compiled version of std with `rustup target add` + + Building std from source with `cargo build -Z build-std` + + Using `#![no_std]` at the crate root, so you won't need `std` in the first + place. +- You are developing the compiler itself and haven't built libstd from source. + You can usually build it with `x.py build library/std`. More information + about x.py is available in the [rustc-dev-guide]. + +[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html#building-the-compiler diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index e184e929b0745..aa88233209940 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -901,7 +901,7 @@ impl HandlerInner { fn span_bug(&mut self, sp: impl Into, msg: &str) -> ! { self.emit_diag_at_span(Diagnostic::new(Bug, msg), sp); - panic!(ExplicitBug); + panic::panic_any(ExplicitBug); } fn emit_diag_at_span(&mut self, mut diag: Diagnostic, sp: impl Into) { @@ -955,7 +955,7 @@ impl HandlerInner { fn bug(&mut self, msg: &str) -> ! { self.emit_diagnostic(&Diagnostic::new(Bug, msg)); - panic!(ExplicitBug); + panic::panic_any(ExplicitBug); } fn delay_as_bug(&mut self, diagnostic: Diagnostic) { diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1c16dc026670b..6487b23a6a60a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -358,7 +358,7 @@ impl GenericArgs<'_> { .iter() .filter(|arg| !arg.is_synthetic()) .map(|arg| arg.span()) - .fold_first(|span1, span2| span1.to(span2)) + .reduce(|span1, span2| span1.to(span2)) } /// Returns span encompassing arguments and their surrounding `<>` or `()` diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index efc516a662fb7..c69a9b063aeca 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -6,7 +6,6 @@ #![feature(const_fn)] // For the unsizing cast on `&[]` #![feature(const_panic)] #![feature(in_band_lifetimes)] -#![feature(iterator_fold_self)] #![feature(once_cell)] #![feature(or_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_index/src/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs index 6cc3e9427d1a7..c11b98e77aa58 100644 --- a/compiler/rustc_index/src/bit_set/tests.rs +++ b/compiler/rustc_index/src/bit_set/tests.rs @@ -1,6 +1,7 @@ use super::*; extern crate test; +use std::hint::black_box; use test::Bencher; #[test] @@ -364,3 +365,36 @@ fn union_hybrid_sparse_full_small_domain(b: &mut Bencher) { sparse.union(&dense); }) } + +#[bench] +fn bench_insert(b: &mut Bencher) { + let mut bs = BitSet::new_filled(99999usize); + b.iter(|| { + black_box(bs.insert(black_box(100u32))); + }); +} + +#[bench] +fn bench_remove(b: &mut Bencher) { + let mut bs = BitSet::new_filled(99999usize); + b.iter(|| { + black_box(bs.remove(black_box(100u32))); + }); +} + +#[bench] +fn bench_iter(b: &mut Bencher) { + let bs = BitSet::new_filled(99999usize); + b.iter(|| { + bs.iter().map(|b: usize| black_box(b)).for_each(drop); + }); +} + +#[bench] +fn bench_intersect(b: &mut Bencher) { + let mut ba: BitSet = BitSet::new_filled(99999usize); + let bb = BitSet::new_filled(99999usize); + b.iter(|| { + ba.intersect(black_box(&bb)); + }); +} diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md b/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md index e0b2c0bffeeb3..0a7da8c80639c 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md @@ -1,4 +1,3 @@ - Lexical Region Resolution was removed in https://github.com/rust-lang/rust/pull/64790. Rust now uses Non-lexical lifetimes. For more info, please see the [borrowck diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 8bd9dad785c4b..58a9064b9195b 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -39,6 +39,7 @@ use rustc_session::SessionLintStore; use rustc_span::lev_distance::find_best_match_for_name; use rustc_span::{symbol::Symbol, MultiSpan, Span, DUMMY_SP}; use rustc_target::abi::LayoutOf; +use tracing::debug; use std::cell::Cell; use std::slice; @@ -336,6 +337,20 @@ impl LintStore { } } + /// True if this symbol represents a lint group name. + pub fn is_lint_group(&self, lint_name: Symbol) -> bool { + debug!( + "is_lint_group(lint_name={:?}, lint_groups={:?})", + lint_name, + self.lint_groups.keys().collect::>() + ); + let lint_name_str = &*lint_name.as_str(); + self.lint_groups.contains_key(&lint_name_str) || { + let warnings_name_str = crate::WARNINGS.name_lower(); + lint_name_str == &*warnings_name_str + } + } + /// Checks the name of a lint for its existence, and whether it was /// renamed or removed. Generates a DiagnosticBuilder containing a /// warning for renamed and removed lints. This is over both lint diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 18cd25e5d2aa3..1fc2bd0916757 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -5,7 +5,7 @@ use rustc_ast::attr; use rustc_ast::unwrap_or; use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{struct_span_err, Applicability}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_hir::{intravisit, HirId}; @@ -17,11 +17,15 @@ use rustc_middle::lint::{ }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_session::lint::{builtin, Level, Lint, LintId}; +use rustc_session::lint::{ + builtin::{self, FORBIDDEN_LINT_GROUPS}, + Level, Lint, LintId, +}; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{source_map::MultiSpan, Span, DUMMY_SP}; +use tracing::debug; use std::cmp; @@ -51,6 +55,7 @@ pub struct LintLevelsBuilder<'s> { id_to_set: FxHashMap, cur: u32, warn_about_weird_lints: bool, + store: &'s LintStore, } pub struct BuilderPush { @@ -59,13 +64,14 @@ pub struct BuilderPush { } impl<'s> LintLevelsBuilder<'s> { - pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &LintStore) -> Self { + pub fn new(sess: &'s Session, warn_about_weird_lints: bool, store: &'s LintStore) -> Self { let mut builder = LintLevelsBuilder { sess, sets: LintLevelSets::new(), cur: 0, id_to_set: Default::default(), warn_about_weird_lints, + store, }; builder.process_command_line(sess, store); assert_eq!(builder.sets.list.len(), 1); @@ -120,36 +126,75 @@ impl<'s> LintLevelsBuilder<'s> { if let (Level::Forbid, old_src) = self.sets.get_lint_level(id.lint, self.cur, Some(&specs), &self.sess) { - let mut diag_builder = struct_span_err!( - self.sess, - src.span(), - E0453, - "{}({}) incompatible with previous forbid", - level.as_str(), - src.name(), + // Backwards compatibility check: + // + // We used to not consider `forbid(lint_group)` + // as preventing `allow(lint)` for some lint `lint` in + // `lint_group`. For now, issue a future-compatibility + // warning for this case. + let id_name = id.lint.name_lower(); + let fcw_warning = match old_src { + LintLevelSource::Default => false, + LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol), + LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol), + }; + debug!( + "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}", + fcw_warning, specs, old_src, id_name ); - diag_builder.span_label(src.span(), "overruled by previous forbid"); - match old_src { - LintLevelSource::Default => { - diag_builder.note(&format!( - "`forbid` lint level is the default for {}", - id.to_string() - )); - } - LintLevelSource::Node(_, forbid_source_span, reason) => { - diag_builder.span_label(forbid_source_span, "`forbid` level set here"); - if let Some(rationale) = reason { - diag_builder.note(&rationale.as_str()); + + let decorate_diag_builder = |mut diag_builder: DiagnosticBuilder<'_>| { + diag_builder.span_label(src.span(), "overruled by previous forbid"); + match old_src { + LintLevelSource::Default => { + diag_builder.note(&format!( + "`forbid` lint level is the default for {}", + id.to_string() + )); + } + LintLevelSource::Node(_, forbid_source_span, reason) => { + diag_builder.span_label(forbid_source_span, "`forbid` level set here"); + if let Some(rationale) = reason { + diag_builder.note(&rationale.as_str()); + } + } + LintLevelSource::CommandLine(_, _) => { + diag_builder.note("`forbid` lint level was set on command line"); } } - LintLevelSource::CommandLine(_, _) => { - diag_builder.note("`forbid` lint level was set on command line"); - } + diag_builder.emit(); + }; + if !fcw_warning { + let diag_builder = struct_span_err!( + self.sess, + src.span(), + E0453, + "{}({}) incompatible with previous forbid", + level.as_str(), + src.name(), + ); + decorate_diag_builder(diag_builder); + } else { + self.struct_lint( + FORBIDDEN_LINT_GROUPS, + Some(src.span().into()), + |diag_builder| { + let diag_builder = diag_builder.build(&format!( + "{}({}) incompatible with previous forbid", + level.as_str(), + src.name(), + )); + decorate_diag_builder(diag_builder); + }, + ); } - diag_builder.emit(); - // Retain the forbid lint level - return; + // Retain the forbid lint level, unless we are + // issuing a FCW. In the FCW case, we want to + // respect the new setting. + if !fcw_warning { + return; + } } } specs.insert(id, (level, src)); diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 6f44436e2a010..638b73c27a8d7 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -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; @@ -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::*; @@ -169,7 +169,7 @@ macro_rules! late_lint_passes { ClashingExternDeclarations: ClashingExternDeclarations::new(), DropTraitConstraints: DropTraitConstraints, TemporaryCStringAsPtr: TemporaryCStringAsPtr, - PanicFmt: PanicFmt, + NonPanicFmt: NonPanicFmt, ] ); }; diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs new file mode 100644 index 0000000000000..e98297b692c92 --- /dev/null +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -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> = + 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) +} diff --git a/compiler/rustc_lint/src/panic_fmt.rs b/compiler/rustc_lint/src/panic_fmt.rs deleted file mode 100644 index 4a6aca72acbbe..0000000000000 --- a/compiler/rustc_lint/src/panic_fmt.rs +++ /dev/null @@ -1,155 +0,0 @@ -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, InnerSpan}; - -declare_lint! { - /// The `panic_fmt` lint detects `panic!("..")` with `{` or `}` in the string literal. - /// - /// ### Example - /// - /// ```rust,no_run - /// panic!("{}"); - /// ``` - /// - /// {{produces}} - /// - /// ### Explanation - /// - /// In Rust 2018 and earlier, `panic!("{}")` panics with the message `"{}"`, - /// as a `panic!()` invocation with a single argument does not use `format_args!()`. - /// Rust 2021 interprets this string as format string, which breaks this. - PANIC_FMT, - Warn, - "detect braces in single-argument panic!() invocations", - report_in_external_macro -} - -declare_lint_pass!(PanicFmt => [PANIC_FMT]); - -impl<'tcx> LateLintPass<'tcx> for PanicFmt { - 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() - { - 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 { - let mut expn = f.span.ctxt().outer_expn_data(); - if let Some(id) = expn.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) - { - let fmt = sym.as_str(); - if !fmt.contains(&['{', '}'][..]) { - 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(); - - // Unwrap more levels of macro expansion, as panic_2015!() - // was likely expanded from panic!() and possibly from - // [debug_]assert!(). - for &assert 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(assert, id)) - { - expn = parent; - } - } - - 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(PANIC_FMT, 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 a future Rust edition"); - if expn.call_site.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> = 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(PANIC_FMT, brace_spans.unwrap_or(vec![expn.call_site]), |lint| { - let mut l = lint.build(msg); - l.note("this message is not used as a format string, but will be in a future Rust edition"); - if expn.call_site.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(); - }); - } - } - } - } - } -} diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 4337600384008..da62ad3a6b1cd 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -5,10 +5,48 @@ //! compiler code, rather than using their own custom pass. Those //! lints are all available in `rustc_lint::builtin`. +// ignore-tidy-filelength + use crate::{declare_lint, declare_lint_pass}; use rustc_span::edition::Edition; use rustc_span::symbol::sym; +declare_lint! { + /// The `forbidden_lint_groups` lint detects violations of + /// `forbid` applied to a lint group. Due to a bug in the compiler, + /// these used to be overlooked entirely. They now generate a warning. + /// + /// ### Example + /// + /// ```rust + /// #![forbid(warnings)] + /// #![deny(bad_style)] + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Recommended fix + /// + /// If your crate is using `#![forbid(warnings)]`, + /// we recommend that you change to `#![deny(warnings)]`. + /// + /// ### Explanation + /// + /// Due to a compiler bug, applying `forbid` to lint groups + /// previously had no effect. The bug is now fixed but instead of + /// enforcing `forbid` we issue this future-compatibility warning + /// to avoid breaking existing crates. + pub FORBIDDEN_LINT_GROUPS, + Warn, + "applying forbid to lint-groups", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #81670 ", + edition: None, + }; +} + declare_lint! { /// The `ill_formed_attribute_input` lint detects ill-formed attribute /// inputs that were previously accepted and used in practice. @@ -2888,6 +2926,7 @@ declare_lint_pass! { /// Does nothing as a lint pass, but registers some `Lint`s /// that are used by other parts of the compiler. HardwiredLints => [ + FORBIDDEN_LINT_GROUPS, ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, ARITHMETIC_OVERFLOW, UNCONDITIONAL_PANIC, diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 0bdccf7b5f073..ca73481b21699 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -5,7 +5,10 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; -use rustc_session::lint::{builtin, Level, Lint, LintId}; +use rustc_session::lint::{ + builtin::{self, FORBIDDEN_LINT_GROUPS}, + Level, Lint, LintId, +}; use rustc_session::{DiagnosticMessageId, Session}; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::{DesugaringKind, ExpnKind, MultiSpan}; @@ -89,7 +92,12 @@ impl LintLevelSets { // If we're about to issue a warning, check at the last minute for any // directives against the warnings "lint". If, for example, there's an // `allow(warnings)` in scope then we want to respect that instead. - if level == Level::Warn { + // + // We exempt `FORBIDDEN_LINT_GROUPS` from this because it specifically + // triggers in cases (like #80988) where you have `forbid(warnings)`, + // and so if we turned that into an error, it'd defeat the purpose of the + // future compatibility warning. + if level == Level::Warn && LintId::of(lint) != LintId::of(FORBIDDEN_LINT_GROUPS) { let (warnings_level, warnings_src) = self.get_lint_id_level(LintId::of(builtin::WARNINGS), idx, aux); if let Some(configured_warning_level) = warnings_level { diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index e79adcdb54598..791d5060fe5c7 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -3,7 +3,7 @@ use crate::ty::{tls, TyCtxt}; use rustc_span::{MultiSpan, Span}; use std::fmt; -use std::panic::Location; +use std::panic::{panic_any, Location}; #[cold] #[inline(never)] @@ -32,7 +32,7 @@ fn opt_span_bug_fmt>( match (tcx, span) { (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg), (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg), - (None, _) => panic!(msg), + (None, _) => panic_any(msg), } }); unreachable!(); diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index ea04e7bb44b3b..53c3adcc20c02 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -17,6 +17,7 @@ Core encoding and decoding interfaces. #![feature(min_specialization)] #![feature(vec_spare_capacity)] #![feature(core_intrinsics)] +#![feature(int_bits_const)] #![feature(maybe_uninit_slice)] #![feature(new_uninit)] #![cfg_attr(test, feature(test))] diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs index 3e2aab5125ab7..a2bcf2c251d7a 100644 --- a/compiler/rustc_serialize/tests/leb128.rs +++ b/compiler/rustc_serialize/tests/leb128.rs @@ -1,3 +1,4 @@ +#![feature(int_bits_const)] #![feature(maybe_uninit_slice)] #![feature(maybe_uninit_uninit_array)] diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs index 3a757e5f0075d..47f14fa6b7a74 100644 --- a/compiler/rustc_session/src/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -113,6 +113,8 @@ pub fn make_target_lib_path(sysroot: &Path, target_triple: &str) -> PathBuf { sysroot.join(&relative_target_lib_path(sysroot, target_triple)) } +// This function checks if sysroot is found using env::args().next(), and if it +// is not found, uses env::current_exe() to imply sysroot. pub fn get_or_default_sysroot() -> PathBuf { // Follow symlinks. If the resolved path is relative, make it absolute. fn canonicalize(path: PathBuf) -> PathBuf { @@ -123,15 +125,51 @@ pub fn get_or_default_sysroot() -> PathBuf { fix_windows_verbatim_for_gcc(&path) } - match env::current_exe() { - Ok(exe) => { - let mut p = canonicalize(exe); - p.pop(); - p.pop(); - p + // Use env::current_exe() to get the path of the executable following + // symlinks/canonicalizing components. + fn from_current_exe() -> PathBuf { + match env::current_exe() { + Ok(exe) => { + let mut p = canonicalize(exe); + p.pop(); + p.pop(); + p + } + Err(e) => panic!("failed to get current_exe: {}", e), + } + } + + // Use env::args().next() to get the path of the executable without + // following symlinks/canonicalizing any component. This makes the rustc + // binary able to locate Rust libraries in systems using content-addressable + // storage (CAS). + fn from_env_args_next() -> Option { + match env::args_os().next() { + Some(first_arg) => { + let mut p = PathBuf::from(first_arg); + + // Check if sysroot is found using env::args().next() only if the rustc in argv[0] + // is a symlink (see #79253). We might want to change/remove it to conform with + // https://www.gnu.org/prep/standards/standards.html#Finding-Program-Files in the + // future. + if fs::read_link(&p).is_err() { + // Path is not a symbolic link or does not exist. + return None; + } + + p.pop(); + p.pop(); + let mut libdir = PathBuf::from(&p); + libdir.push(find_libdir(&p).as_ref()); + if libdir.exists() { Some(p) } else { None } + } + None => None, } - Err(e) => panic!("failed to get current_exe: {}", e), } + + // Check if sysroot is found using env::args().next(), and if is not found, + // use env::current_exe() to imply sysroot. + from_env_args_next().unwrap_or(from_current_exe()) } // The name of the directory rustc expects libraries to be located. diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 0a1ecced49abc..a49979fb7aa18 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -102,6 +102,7 @@ #![feature(fn_traits)] #![feature(fundamental)] #![feature(inplace_iteration)] +#![feature(int_bits_const)] #![feature(lang_items)] #![feature(layout_for_ptr)] #![feature(maybe_uninit_ref)] diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 9c7343e8cbf5a..dd98f806451d8 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -17,6 +17,7 @@ #![feature(binary_heap_retain)] #![feature(inplace_iteration)] #![feature(iter_map_while)] +#![feature(int_bits_const)] #![feature(vecdeque_binary_search)] #![feature(slice_group_by)] #![feature(vec_extend_from_within)] diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index c961e2964a943..6b42d456205cd 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -2028,7 +2028,8 @@ pub trait Iterator { self.try_fold((), call(f)) } - /// An iterator method that applies a function, producing a single, final value. + /// Folds every element into an accumulator by applying an operation, + /// returning the final result. /// /// `fold()` takes two arguments: an initial value, and a closure with two /// arguments: an 'accumulator', and an element. The closure returns the value that @@ -2049,6 +2050,9 @@ pub trait Iterator { /// may not terminate for infinite iterators, even on traits for which a /// result is determinable in finite time. /// + /// Note: [`reduce()`] can be used to use the first element as the initial + /// value, if the accumulator type and item type is the same. + /// /// # Note to Implementors /// /// Several of the other (forward) methods have default implementations in @@ -2104,6 +2108,8 @@ pub trait Iterator { /// // they're the same /// assert_eq!(result, result2); /// ``` + /// + /// [`reduce()`]: Iterator::reduce #[doc(alias = "reduce")] #[doc(alias = "inject")] #[inline] @@ -2120,10 +2126,15 @@ pub trait Iterator { accum } - /// The same as [`fold()`], but uses the first element in the - /// iterator as the initial value, folding every subsequent element into it. - /// If the iterator is empty, return [`None`]; otherwise, return the result - /// of the fold. + /// Reduces the elements to a single one, by repeatedly applying a reducing + /// operation. + /// + /// If the iterator is empty, returns [`None`]; otherwise, returns the + /// result of the reduction. + /// + /// For iterators with at least one element, this is the same as [`fold()`] + /// with the first element of the iterator as the initial value, folding + /// every subsequent element into it. /// /// [`fold()`]: Iterator::fold /// @@ -2132,13 +2143,11 @@ pub trait Iterator { /// Find the maximum value: /// /// ``` - /// #![feature(iterator_fold_self)] - /// /// fn find_max(iter: I) -> Option /// where I: Iterator, /// I::Item: Ord, /// { - /// iter.fold_first(|a, b| { + /// iter.reduce(|a, b| { /// if a >= b { a } else { b } /// }) /// } @@ -2149,8 +2158,8 @@ pub trait Iterator { /// assert_eq!(find_max(b.iter()), None); /// ``` #[inline] - #[unstable(feature = "iterator_fold_self", issue = "68125")] - fn fold_first(mut self, f: F) -> Option + #[stable(feature = "iterator_fold_self", since = "1.51.0")] + fn reduce(mut self, f: F) -> Option where Self: Sized, F: FnMut(Self::Item, Self::Item) -> Self::Item, @@ -2647,7 +2656,7 @@ pub trait Iterator { move |x, y| cmp::max_by(x, y, &mut compare) } - self.fold_first(fold(compare)) + self.reduce(fold(compare)) } /// Returns the element that gives the minimum value from the @@ -2707,7 +2716,7 @@ pub trait Iterator { move |x, y| cmp::min_by(x, y, &mut compare) } - self.fold_first(fold(compare)) + self.reduce(fold(compare)) } /// Reverses an iterator's direction. diff --git a/library/core/src/macros/panic.md b/library/core/src/macros/panic.md index a02e74d5e5a4d..6e502426df906 100644 --- a/library/core/src/macros/panic.md +++ b/library/core/src/macros/panic.md @@ -10,22 +10,23 @@ tests. `panic!` is closely tied with the `unwrap` method of both `panic!` when they are set to [`None`] or [`Err`] variants. This macro is used to inject panic into a Rust thread, causing the thread to -panic entirely. Each thread's panic can be reaped as the [`Box`]`<`[`Any`]`>` type, -and the single-argument form of the `panic!` macro will be the value which -is transmitted. +panic entirely. This macro panics with a string and uses the [`format!`] syntax +for building the message. + +Each thread's panic can be reaped as the [`Box`]`<`[`Any`]`>` type, +which contains either a `&str` or `String` for regular `panic!()` invocations. +To panic with a value of another other type, [`panic_any`] can be used. [`Result`] enum is often a better solution for recovering from errors than using the `panic!` macro. This macro should be used to avoid proceeding using incorrect values, such as from external sources. Detailed information about error handling is found in the [book]. -The multi-argument form of this macro panics with a string and has the -[`format!`] syntax for building a string. - See also the macro [`compile_error!`], for raising errors during compilation. [ounwrap]: Option::unwrap [runwrap]: Result::unwrap +[`panic_any`]: ../std/panic/fn.panic_any.html [`Box`]: ../std/boxed/struct.Box.html [`Any`]: crate::any::Any [`format!`]: ../std/macro.format.html @@ -42,6 +43,6 @@ program with code `101`. # #![allow(unreachable_code)] panic!(); panic!("this is a terrible mistake!"); -panic!(4); // panic with the value of 4 to be collected elsewhere panic!("this is a {} {message}", "fancy", message = "message"); +std::panic::panic_any(4); // panic with the value of 4 to be collected elsewhere ``` diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 96affd17cc520..8fdd7c9e5d7fb 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -32,9 +32,10 @@ macro_rules! int_impl { /// # Examples /// /// ``` + /// #![feature(int_bits_const)] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")] /// ``` - #[stable(feature = "int_bits_const", since = "1.51.0")] + #[unstable(feature = "int_bits_const", issue = "76904")] pub const BITS: u32 = $BITS; /// Converts a string slice in a given base to an integer. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index aee424b9b1392..9fccf3f72ce1a 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -32,9 +32,10 @@ macro_rules! uint_impl { /// # Examples /// /// ``` + /// #![feature(int_bits_const)] #[doc = concat!("assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");")] /// ``` - #[stable(feature = "int_bits_const", since = "1.51.0")] + #[unstable(feature = "int_bits_const", issue = "76904")] pub const BITS: u32 = $BITS; /// Converts a string slice in a given base to an integer. diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 26dbcb8569b43..bc0e3e059c917 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -70,6 +70,7 @@ #![feature(partition_point)] #![feature(once_cell)] #![feature(unsafe_block_in_unsafe_fn)] +#![feature(int_bits_const)] #![feature(nonzero_leading_trailing_zeros)] #![feature(const_option)] #![feature(integer_atomics)] diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 99a0c67fc11b9..9ce9c477ec0f0 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -18,6 +18,7 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/" )] #![feature(core_intrinsics)] +#![feature(int_bits_const)] #![feature(lang_items)] #![feature(nll)] #![feature(panic_unwind)] diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 21060182d60bc..c9c8f68cd9cce 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -826,7 +826,7 @@ impl OsStr { /// assert!(!OsString::from("Ferrös").eq_ignore_ascii_case("FERRÖS")); /// ``` #[unstable(feature = "osstring_ascii", issue = "70516")] - pub fn eq_ignore_ascii_case>(&self, other: &S) -> bool { + pub fn eq_ignore_ascii_case>(&self, other: S) -> bool { self.inner.eq_ignore_ascii_case(&other.as_ref().inner) } } diff --git a/library/term/src/terminfo/parm/tests.rs b/library/term/src/terminfo/parm/tests.rs index b975bd2d19882..1cc0967c8f42e 100644 --- a/library/term/src/terminfo/parm/tests.rs +++ b/library/term/src/terminfo/parm/tests.rs @@ -77,15 +77,15 @@ fn test_comparison_ops() { for &(op, bs) in v.iter() { let s = format!("%{{1}}%{{2}}%{}%d", op); let res = expand(s.as_bytes(), &[], &mut Variables::new()); - assert!(res.is_ok(), res.unwrap_err()); + assert!(res.is_ok(), "{}", res.unwrap_err()); assert_eq!(res.unwrap(), vec![b'0' + bs[0]]); let s = format!("%{{1}}%{{1}}%{}%d", op); let res = expand(s.as_bytes(), &[], &mut Variables::new()); - assert!(res.is_ok(), res.unwrap_err()); + assert!(res.is_ok(), "{}", res.unwrap_err()); assert_eq!(res.unwrap(), vec![b'0' + bs[1]]); let s = format!("%{{2}}%{{1}}%{}%d", op); let res = expand(s.as_bytes(), &[], &mut Variables::new()); - assert!(res.is_ok(), res.unwrap_err()); + assert!(res.is_ok(), "{}", res.unwrap_err()); assert_eq!(res.unwrap(), vec![b'0' + bs[2]]); } } @@ -95,13 +95,13 @@ fn test_conditionals() { let mut vars = Variables::new(); let s = b"\\E[%?%p1%{8}%<%t3%p1%d%e%p1%{16}%<%t9%p1%{8}%-%d%e38;5;%p1%d%;m"; let res = expand(s, &[Number(1)], &mut vars); - assert!(res.is_ok(), res.unwrap_err()); + assert!(res.is_ok(), "{}", res.unwrap_err()); assert_eq!(res.unwrap(), "\\E[31m".bytes().collect::>()); let res = expand(s, &[Number(8)], &mut vars); - assert!(res.is_ok(), res.unwrap_err()); + assert!(res.is_ok(), "{}", res.unwrap_err()); assert_eq!(res.unwrap(), "\\E[90m".bytes().collect::>()); let res = expand(s, &[Number(42)], &mut vars); - assert!(res.is_ok(), res.unwrap_err()); + assert!(res.is_ok(), "{}", res.unwrap_err()); assert_eq!(res.unwrap(), "\\E[38;5;42m".bytes().collect::>()); } diff --git a/library/test/src/tests.rs b/library/test/src/tests.rs index 99e12c973c4a2..f0586d510dbdb 100644 --- a/library/test/src/tests.rs +++ b/library/test/src/tests.rs @@ -199,7 +199,7 @@ fn test_should_panic_bad_message() { fn test_should_panic_non_string_message_type() { use crate::tests::TrFailedMsg; fn f() { - panic!(1i32); + std::panic::panic_any(1i32); } let expected = "foobar"; let failed_msg = format!( diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index 44d5d9564f267..70df5170b21c1 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -378,7 +378,7 @@ C library default allocator5 since version 1.32.0 (2019-01-17)[39]. -```ignore +```rust,no_run fn main() { let mut x = Box::new([0; 1024]); diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md index 64cbbbb003585..3e616f226ed76 100644 --- a/src/doc/rustc/src/lints/levels.md +++ b/src/doc/rustc/src/lints/levels.md @@ -62,7 +62,7 @@ warning: unused variable: `x` A 'deny' lint produces an error if you violate it. For example, this code runs into the `exceeding_bitshifts` lint. -```rust,ignore +```rust,no_run fn main() { 100u8 << 10; } @@ -232,7 +232,7 @@ pub fn foo() {} This is the maximum level for all lints. So for example, if we take our code sample from the "deny" lint level above: -```rust,ignore +```rust,no_run fn main() { 100u8 << 10; } diff --git a/src/doc/rustc/src/lints/listing/index.md b/src/doc/rustc/src/lints/listing/index.md index 18cd2fe32a3cc..97aa2caf91508 100644 --- a/src/doc/rustc/src/lints/listing/index.md +++ b/src/doc/rustc/src/lints/listing/index.md @@ -2,4 +2,4 @@ This section lists out all of the lints, grouped by their default lint levels. -You can also see this list by running `rustc -W help`. \ No newline at end of file +You can also see this list by running `rustc -W help`. diff --git a/src/doc/rustc/src/what-is-rustc.md b/src/doc/rustc/src/what-is-rustc.md index 9dcc9f7daa9ff..39a05cfe20534 100644 --- a/src/doc/rustc/src/what-is-rustc.md +++ b/src/doc/rustc/src/what-is-rustc.md @@ -39,7 +39,7 @@ $ .\hello.exe # on Windows Note that we only ever pass `rustc` the *crate root*, not every file we wish to compile. For example, if we had a `main.rs` that looked like this: -```rust,ignore +```rust,ignore (needs-multiple-files) mod foo; fn main() { @@ -49,7 +49,7 @@ fn main() { And a `foo.rs` that had this: -```rust,ignore +```rust,no_run pub fn hello() { println!("Hello, world!"); } diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 5128ff13b7a79..abdc2e4025d0e 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -47,8 +47,7 @@ all type errors and name resolution errors with function bodies. Note that this work for anything outside a function body: since Rustdoc documents your types, it has to know what those types are! For example, this code will work regardless of the platform: - -```ignore +```rust,ignore (platform-specific,rustdoc-specific-behavior) pub fn f() { use std::os::windows::ffi::OsStrExt; } @@ -56,7 +55,7 @@ pub fn f() { but this will not, because the unknown type is part of the function signature: -```ignore +```rust,ignore (platform-specific,rustdoc-specific-behavior) pub fn f() -> std::os::windows::ffi::EncodeWide<'static> { unimplemented!() } diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index 387d86189b08f..8e3c622818954 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -5,12 +5,13 @@ that examples within your documentation are up to date and working. The basic idea is this: -```ignore +```rust,no_run /// # Examples /// /// ``` /// let x = 5; /// ``` +# fn f() {} ``` The triple backticks start and end code blocks. If this were in a file named `foo.rs`, @@ -78,12 +79,13 @@ Sometimes, you need some setup code, or other things that would distract from your example, but are important to make the tests work. Consider an example block that looks like this: -```ignore +```rust,no_run /// ``` /// /// Some documentation. /// # fn foo() {} // this function will be hidden /// println!("Hello, World!"); /// ``` +# fn f() {} ``` It will render like this: @@ -196,12 +198,13 @@ When writing an example, it is rarely useful to include a complete error handling, as it would add significant amounts of boilerplate code. Instead, you may want the following: -```ignore +```rust,no_run /// ``` /// use std::io; /// let mut input = String::new(); /// io::stdin().read_line(&mut input)?; /// ``` +# fn f() {} ``` The problem is that `?` returns a `Result` and test functions don't @@ -210,7 +213,7 @@ return anything, so this will give a mismatched types error. You can get around this limitation by manually adding a `main` that returns `Result`, because `Result` implements the `Termination` trait: -```ignore +```rust,no_run /// A doc test using ? /// /// ``` @@ -222,12 +225,13 @@ You can get around this limitation by manually adding a `main` that returns /// Ok(()) /// } /// ``` +# fn f() {} ``` Together with the `# ` from the section above, you arrive at a solution that appears to the reader as the initial idea but works with doc tests: -```ignore +```rust,no_run /// ``` /// use std::io; /// # fn main() -> io::Result<()> { @@ -236,18 +240,20 @@ appears to the reader as the initial idea but works with doc tests: /// # Ok(()) /// # } /// ``` +# fn f() {} ``` As of version 1.34.0, one can also omit the `fn main()`, but you will have to disambiguate the error type: -```ignore +```rust,no_run /// ``` /// use std::io; /// let mut input = String::new(); /// io::stdin().read_line(&mut input)?; /// # Ok::<(), io::Error>(()) /// ``` +# fn f() {} ``` This is an unfortunate consequence of the `?` operator adding an implicit @@ -417,7 +423,7 @@ Another possible use of `#[cfg(doctest)]` is to test doctests that are included without including it in your main documentation. For example, you could write this into your `lib.rs` to test your README as part of your doctests: -```rust,ignore +```rust,no_run #![feature(external_doc)] #[doc(include = "../README.md")] diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md index 41736e5ee3a7e..0a7dedb25a124 100644 --- a/src/doc/rustdoc/src/how-to-write-documentation.md +++ b/src/doc/rustdoc/src/how-to-write-documentation.md @@ -7,7 +7,7 @@ implementation detail, or leaves readers with unanswered questions. There are a few tenets to Rust documentation that can help guide anyone through the process of documenting libraries so that everyone has an ample opportunity -to use the code. +to use the code. This chapter covers not only how to write documentation but specifically how to write **good** documentation. It is important to be as clear @@ -19,31 +19,31 @@ then it should be documented. Documenting a crate should begin with front-page documentation. As an example, the [`hashbrown`] crate level documentation summarizes the role of -the crate, provides links to explain technical details, and explains why you -would want to use the crate. +the crate, provides links to explain technical details, and explains why you +would want to use the crate. -After introducing the crate, it is important that the front-page gives +After introducing the crate, it is important that the front-page gives an example of how to use the crate in a real world setting. Stick to the library's role in the example, but do so without shortcuts to benefit users who -may copy and paste the example to get started. +may copy and paste the example to get started. [`futures`] uses inline comments to explain line by line -the complexities of using a [`Future`], because a person's first exposure to +the complexities of using a [`Future`], because a person's first exposure to rust's [`Future`] may be this example. -The [`backtrace`] documentation walks through the whole process, explaining +The [`backtrace`] documentation walks through the whole process, explaining changes made to the `Cargo.toml` file, passing command line arguments to the -compiler, and shows a quick example of backtrace in the wild. +compiler, and shows a quick example of backtrace in the wild. Finally, the front-page can eventually become a comprehensive reference how to use a crate, like [`regex`]. In this front page, all -requirements are outlined, the edge cases shown, and practical examples +requirements are outlined, the edge cases shown, and practical examples provided. The front page goes on to show how to use regular expressions then concludes with crate features. Don't worry about comparing your crate, which is just beginning, to other more developed crates. To get the documentation to something more polished, start -incrementally and put in an introduction, example, and features. Rome was not +incrementally and put in an introduction, example, and features. Rome was not built in a day! The first lines within the `lib.rs` will compose the front-page, and they @@ -51,7 +51,7 @@ use a different convention than the rest of the rustdocs. Lines should start with `//!` which indicate module-level or crate-level documentation. Here's a quick example of the difference: -```rust,ignore +```rust,no_run //! Fast and easy queue abstraction. //! //! Provides an abstraction over a queue. When the abstraction is used @@ -64,13 +64,13 @@ Here's a quick example of the difference: /// This module makes it easy. pub mod easy { - /// Use the abstract function to do this specific thing. - pub fn abstract() {} + /// Use the abstraction function to do this specific thing. + pub fn abstraction() {} } ``` -Ideally, this first line of documentation is a sentence without highly +Ideally, this first line of documentation is a sentence without highly technical details, but with a good description of where this crate fits within the rust ecosystem. Users should know whether this crate meets their use case after reading this line. @@ -95,7 +95,7 @@ It is recommended that each item's documentation follows this basic structure: This basic structure should be straightforward to follow when writing your documentation; while you might think that a code example is trivial, -the examples are really important because they can help users understand +the examples are really important because they can help users understand what an item is, how it is used, and for what purpose it exists. Let's see an example coming from the [standard library] by taking a look at the @@ -133,7 +133,7 @@ for argument in env::args() { [`args_os`]: ./fn.args_os.html `````` -Everything before the first empty line will be reused to describe the component +Everything before the first empty line will be reused to describe the component in searches and module overviews. For example, the function `std::env::args()` above will be shown on the [`std::env`] module documentation. It is good practice to keep the summary to one line: concise writing is a goal of good @@ -225,7 +225,7 @@ details on the exact syntax supported. [commonmark markdown specification]: https://commonmark.org/ [commonmark quick reference]: https://commonmark.org/help/ [env::args]: https://doc.rust-lang.org/stable/std/env/fn.args.html -[`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html +[`Future`]: https://doc.rust-lang.org/std/future/trait.Future.html [`futures`]: https://docs.rs/futures/0.3.5/futures/ [`hashbrown`]: https://docs.rs/hashbrown/0.8.2/hashbrown/ [`regex`]: https://docs.rs/regex/1.3.9/regex/ diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index 41292b3d83841..cce3623dc8f49 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -3,10 +3,11 @@ `rustdoc` provides lints to help you writing and testing your documentation. You can use them like any other lints by doing this: -```rust,ignore +```rust #![allow(missing_docs)] // allows the lint, no diagnostics will be reported #![warn(missing_docs)] // warn if there are missing docs #![deny(missing_docs)] // error if there are missing docs +# //! Crate docs. ``` Here is the list of the lints provided by `rustdoc`: diff --git a/src/doc/rustdoc/src/passes.md b/src/doc/rustdoc/src/passes.md index 081e477de8010..140b832f19a54 100644 --- a/src/doc/rustdoc/src/passes.md +++ b/src/doc/rustdoc/src/passes.md @@ -32,8 +32,9 @@ Without this pass, these items will remain in the output. When you write a doc comment like this: -```rust,ignore +```rust,no_run /// This is a documentation comment. +# fn f() {} ``` There's a space between the `///` and that `T`. That spacing isn't intended @@ -52,9 +53,10 @@ documentation string. For example: -```rust,ignore +```rust,no_run #[doc = "This is the first line."] #[doc = "This is the second line."] +# fn f() {} ``` Gets collapsed into a single doc string of @@ -68,7 +70,7 @@ This is the second line. This removes documentation for any non-public items, so for example: -```rust,ignore +```rust,no_run /// These are private docs. struct Private; diff --git a/src/doc/rustdoc/src/references.md b/src/doc/rustdoc/src/references.md index 1e050e321d2e3..b0e2437392c95 100644 --- a/src/doc/rustdoc/src/references.md +++ b/src/doc/rustdoc/src/references.md @@ -3,7 +3,7 @@ There are many great `rustdoc` references out there. If you know of other great resources, please submit a pull request! -## Official +## Official - [Learn Rust] - [Rust By Example] @@ -11,7 +11,7 @@ If you know of other great resources, please submit a pull request! - [RFC 1574: More API Documentation Conventions] - [RFC 1946: Intra Rustdoc Links] -## Community +## Community - [API Guidelines] - [Github tagged RFCs] - [Github tagged issues] @@ -28,4 +28,4 @@ If you know of other great resources, please submit a pull request! [RFC 1946: Intra Rustdoc Links]: https://rust-lang.github.io/rfcs/1946-intra-rustdoc-links.html [RFC (stalled) front page styleguide]: https://github.com/rust-lang/rfcs/pull/1687 [Rust By Example]: https://doc.rust-lang.org/stable/rust-by-example/meta/doc.html -[Rust Reference]: https://doc.rust-lang.org/stable/reference/comments.html#doc-comments \ No newline at end of file +[Rust Reference]: https://doc.rust-lang.org/stable/reference/comments.html#doc-comments diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index ef143c8727ee9..52f2a3728fabb 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -7,9 +7,10 @@ The most basic function of `#[doc]` is to handle the actual documentation text. That is, `///` is syntax sugar for `#[doc]`. This means that these two are the same: -```rust,ignore +```rust,no_run /// This is a doc comment. #[doc = " This is a doc comment."] +# fn f() {} ``` (Note the leading space in the attribute version.) @@ -18,16 +19,18 @@ In most cases, `///` is easier to use than `#[doc]`. One case where the latter i when generating documentation in macros; the `collapse-docs` pass will combine multiple `#[doc]` attributes into a single doc comment, letting you generate code like this: -```rust,ignore +```rust,no_run #[doc = "This is"] #[doc = " a "] #[doc = "doc comment"] +# fn f() {} ``` Which can feel more flexible. Note that this would generate this: -```rust,ignore +```rust,no_run #[doc = "This is\n a \ndoc comment"] +# fn f() {} ``` but given that docs are rendered via Markdown, it will remove these newlines. @@ -45,7 +48,7 @@ These options control how the docs look at a crate level. This form of the `doc` attribute lets you control the favicon of your docs. -```rust,ignore +```rust,no_run #![doc(html_favicon_url = "https://example.com/favicon.ico")] ``` @@ -59,7 +62,7 @@ If you don't use this attribute, there will be no favicon. This form of the `doc` attribute lets you control the logo in the upper left hand side of the docs. -```rust,ignore +```rust,no_run #![doc(html_logo_url = "https://example.com/logo.jpg")] ``` @@ -73,7 +76,7 @@ If you don't use this attribute, there will be no logo. This form of the `doc` attribute lets you control where the "run" buttons on your documentation examples make requests to. -```rust,ignore +```rust,no_run #![doc(html_playground_url = "https://playground.example.com/")] ``` @@ -88,7 +91,7 @@ When a feature is unstable, an issue number for tracking the feature must be given. `rustdoc` uses this number, plus the base URL given here, to link to the tracking issue. -```rust,ignore +```rust,no_run #![doc(issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/")] ``` @@ -103,7 +106,7 @@ available. If that is not available, then it will use the `html_root_url` value in the extern crate if it is available. If that is not available, then the extern items will not be linked. -```rust,ignore +```rust,no_run #![doc(html_root_url = "https://docs.rs/serde/1.0")] ``` @@ -112,7 +115,7 @@ the extern items will not be linked. By default, `rustdoc` will include the source code of your program, with links to it in the docs. But if you include this: -```rust,ignore +```rust,no_run #![doc(html_no_source)] ``` @@ -123,7 +126,7 @@ it will not. By default, `rustdoc` will automatically add a line with `extern crate my_crate;` into each doctest. But if you include this: -```rust,ignore +```rust,no_run #![doc(test(no_crate_inject))] ``` @@ -134,7 +137,7 @@ it will not. This form of the `doc` attribute allows you to add arbitrary attributes to all your doctests. For example, if you want your doctests to fail if they produce any warnings, you could add this: -```rust,ignore +```rust,no_run #![doc(test(attr(deny(warnings))))] ``` @@ -148,7 +151,7 @@ they are documented. These attributes are used on `use` statements, and control where the documentation shows up. For example, consider this Rust code: -```rust,ignore +```rust,no_run pub use bar::Bar; /// bar docs @@ -156,6 +159,7 @@ pub mod bar { /// the docs for Bar pub struct Bar; } +# fn main() {} ``` The documentation will generate a "Re-exports" section, and say `pub use bar::Bar;`, where @@ -163,9 +167,11 @@ The documentation will generate a "Re-exports" section, and say `pub use bar::Ba If we change the `use` line like this: -```rust,ignore +```rust,no_run #[doc(inline)] pub use bar::Bar; +# pub mod bar { pub struct Bar; } +# fn main() {} ``` Instead, `Bar` will appear in a `Structs` section, just like `Bar` was defined at the @@ -173,7 +179,7 @@ top level, rather than `pub use`'d. Let's change our original example, by making `bar` private: -```rust,ignore +```rust,no_run pub use bar::Bar; /// bar docs @@ -181,6 +187,7 @@ mod bar { /// the docs for Bar pub struct Bar; } +# fn main() {} ``` Here, because `bar` is not public, `Bar` wouldn't have its own page, so there's nowhere @@ -188,7 +195,7 @@ to link to. `rustdoc` will inline these definitions, and so we end up in the sam as the `#[doc(inline)]` above; `Bar` is in a `Structs` section, as if it were defined at the top level. If we add the `no_inline` form of the attribute: -```rust,ignore +```rust,no_run #[doc(no_inline)] pub use bar::Bar; @@ -197,6 +204,7 @@ mod bar { /// the docs for Bar pub struct Bar; } +# fn main() {} ``` Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere. diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index 32dc1e02bb3db..7a444d77c09d1 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -32,7 +32,7 @@ $ rustdoc src/lib.rs This will create a new directory, `doc`, with a website inside! In our case, the main page is located in `doc/lib/index.html`. If you open that up in a web browser, you will see a page with a search bar, and "Crate lib" at the -top, with no contents. +top, with no contents. ## Configuring rustdoc @@ -89,18 +89,18 @@ dependency=/docs/target/debug/deps You can see this with `cargo doc --verbose`. It generates the correct `--crate-name` for us, as well as pointing to -`src/lib.rs`. But what about those other arguments? - - `-o` controls the *o*utput of our docs. Instead of a top-level - `doc` directory, notice that Cargo puts generated documentation under +`src/lib.rs`. But what about those other arguments? + - `-o` controls the *o*utput of our docs. Instead of a top-level + `doc` directory, notice that Cargo puts generated documentation under `target`. That is the idiomatic place for generated files in Cargo projects. - - `-L` flag helps rustdoc find the dependencies your code relies on. + - `-L` flag helps rustdoc find the dependencies your code relies on. If our project used dependencies, we would get documentation for them as well! ## Outer and inner documentation The `///` syntax is used to document the item present after it. That's why it is called an outer documentation. -There is another syntax: `//!`, which is used to document the +There is another syntax: `//!`, which is used to document the item it is present inside. It is called an inner documentation. It is often used when documenting the entire crate, because nothing comes before it: it is the root of the crate. diff --git a/src/doc/rustdoc/src/what-to-include.md b/src/doc/rustdoc/src/what-to-include.md index 878c75baae727..9683f519be121 100644 --- a/src/doc/rustdoc/src/what-to-include.md +++ b/src/doc/rustdoc/src/what-to-include.md @@ -38,10 +38,10 @@ warning: 1 warning emitted As a library author, adding the lint `#![deny(missing_docs)]` is a great way to ensure the project does not drift away from being documented well, and -`#![warn(missing_docs)]` is a good way to move towards comprehensive +`#![warn(missing_docs)]` is a good way to move towards comprehensive documentation. In addition to docs, `#![deny(missing_doc_code_examples)]` ensures each function contains a usage example. In our example above, the -warning is resolved by adding crate level documentation. +warning is resolved by adding crate level documentation. There are more lints in the upcoming chapter [Lints][rustdoc-lints]. @@ -58,7 +58,7 @@ users to figure out how to put the `async` code into their own runtime. It is preferred that `unwrap()` not be used inside an example, and some of the error handling components be hidden if they make the example too difficult to -follow. +follow. ``````text /// Example @@ -66,9 +66,9 @@ follow. /// let fourtytwo = "42".parse::()?; /// println!("{} + 10 = {}", fourtytwo, fourtytwo+10); /// ``` -`````` +`````` -When rustdoc wraps that in a main function, it will fail to compile because the +When rustdoc wraps that in a main function, it will fail to compile because the `ParseIntError` trait is not implemented. In order to help both your audience and your test suite, this example needs some additional code: @@ -81,17 +81,17 @@ and your test suite, this example needs some additional code: /// # Ok(()) /// # } /// ``` -`````` +`````` The example is the same on the doc page, but has that extra information -available to anyone trying to use your crate. More about tests in the -upcoming [Documentation tests] chapter. +available to anyone trying to use your crate. More about tests in the +upcoming [Documentation tests] chapter. ## What to Exclude Certain parts of your public interface may be included by default in the output of rustdoc. The attribute `#[doc(hidden)]` can hide implementation details -to encourage idiomatic use of the crate. +to encourage idiomatic use of the crate. For example, an internal `macro!` that makes the crate easier to implement can become a footgun for users when it appears in the public documentation. An @@ -101,11 +101,11 @@ detailed in the [API Guidelines]. ## Customizing the output It is possible to pass a custom css file to `rustdoc` and style the -documentation. +documentation. ```bash rustdoc --extend-css custom.css src/lib.rs -``` +``` A good example of using this feature to create a dark theme is documented [on this blog]. Just remember, dark theme is already included in the rustdoc output @@ -122,4 +122,4 @@ Here is an example of a new theme, [Ayu]. [API Guidelines]: https://rust-lang.github.io/api-guidelines/documentation.html#rustdoc-does-not-show-unhelpful-implementation-details-c-hidden [Documentation tests]: documentation-tests.md [on this blog]: https://blog.guillaume-gomez.fr/articles/2016-09-16+Generating+doc+with+rustdoc+and+a+custom+theme -[rustdoc-lints]: lints.md \ No newline at end of file +[rustdoc-lints]: lints.md diff --git a/src/doc/unstable-book/src/compiler-flags/codegen-backend.md b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md index 878c894a6ca70..3c0cd32fae172 100644 --- a/src/doc/unstable-book/src/compiler-flags/codegen-backend.md +++ b/src/doc/unstable-book/src/compiler-flags/codegen-backend.md @@ -15,7 +15,7 @@ named `__rustc_codegen_backend` with a signature of `fn() -> Box(_t: T) { } fn main() { // works must_be_valid( MaybeValid(True) ); - + // compiler error - trait bound not satisfied // must_be_valid( MaybeValid(False) ); } @@ -80,7 +80,7 @@ where Explicit impls may be either positive or negative. They take the form: -```rust,ignore +```rust,ignore (partial-example) impl<...> AutoTrait for StructName<..> { } impl<...> !AutoTrait for StructName<..> { } ``` @@ -104,4 +104,3 @@ Auto traits cannot have any trait items, such as methods or associated types. Th ## Supertraits Auto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile. - diff --git a/src/doc/unstable-book/src/language-features/custom-test-frameworks.md b/src/doc/unstable-book/src/language-features/custom-test-frameworks.md index 3990b6ad2f080..53ecac9314d79 100644 --- a/src/doc/unstable-book/src/language-features/custom-test-frameworks.md +++ b/src/doc/unstable-book/src/language-features/custom-test-frameworks.md @@ -30,4 +30,3 @@ const WILL_PASS: i32 = 0; #[test_case] const WILL_FAIL: i32 = 4; ``` - diff --git a/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md b/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md index 53e01091f754e..5f3f1b4dd8a31 100644 --- a/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md +++ b/src/doc/unstable-book/src/language-features/infer-static-outlives-requirements.md @@ -42,4 +42,3 @@ struct Bar { x: T, } ``` - diff --git a/src/doc/unstable-book/src/language-features/intrinsics.md b/src/doc/unstable-book/src/language-features/intrinsics.md index bc35c2a030533..a0fb4e743d3f2 100644 --- a/src/doc/unstable-book/src/language-features/intrinsics.md +++ b/src/doc/unstable-book/src/language-features/intrinsics.md @@ -27,4 +27,3 @@ extern "rust-intrinsic" { ``` As with any other FFI functions, these are always `unsafe` to call. - diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 20c7d7dcec8d6..d44c841d48c66 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -15,8 +15,8 @@ For example, `Box` pointers require two lang items, one for allocation and one for deallocation. A freestanding program that uses the `Box` sugar for dynamic allocations via `malloc` and `free`: -```rust,ignore -#![feature(lang_items, box_syntax, start, libc, core_intrinsics)] +```rust,ignore (libc-is-finicky) +#![feature(lang_items, box_syntax, start, libc, core_intrinsics, rustc_private)] #![no_std] use core::intrinsics; use core::panic::PanicInfo; @@ -105,8 +105,8 @@ or overriding the default shim for the C `main` function with your own. The function marked `#[start]` is passed the command line parameters in the same format as C: -```rust,ignore -#![feature(lang_items, core_intrinsics)] +```rust,ignore (libc-is-finicky) +#![feature(lang_items, core_intrinsics, rustc_private)] #![feature(start)] #![no_std] use core::intrinsics; @@ -141,8 +141,8 @@ with `#![no_main]` and then create the appropriate symbol with the correct ABI and the correct name, which requires overriding the compiler's name mangling too: -```rust,ignore -#![feature(lang_items, core_intrinsics)] +```rust,ignore (libc-is-finicky) +#![feature(lang_items, core_intrinsics, rustc_private)] #![feature(start)] #![no_std] #![no_main] diff --git a/src/doc/unstable-book/src/language-features/non-ascii-idents.md b/src/doc/unstable-book/src/language-features/non-ascii-idents.md index 22dae0c89a6ff..847f25ecab132 100644 --- a/src/doc/unstable-book/src/language-features/non-ascii-idents.md +++ b/src/doc/unstable-book/src/language-features/non-ascii-idents.md @@ -19,10 +19,10 @@ const Π: f64 = 3.14f64; ## Changes to the language reference -> **Lexer:** -> IDENTIFIER : ->       XID_start XID_continue\* ->    | `_` XID_continue+ +> **Lexer:**\ +> IDENTIFIER :\ +>       XID_start XID_continue\*\ +>    | `_` XID_continue+ An identifier is any nonempty Unicode string of the following form: diff --git a/src/doc/unstable-book/src/language-features/or-patterns.md b/src/doc/unstable-book/src/language-features/or-patterns.md index 8ebacb44d37cc..55c31add26d77 100644 --- a/src/doc/unstable-book/src/language-features/or-patterns.md +++ b/src/doc/unstable-book/src/language-features/or-patterns.md @@ -11,7 +11,7 @@ a pattern, for example, `Some(A(0) | B(1 | 2))` becomes a valid pattern. ## Examples -```rust,ignore +```rust,no_run #![feature(or_patterns)] pub enum Foo { diff --git a/src/doc/unstable-book/src/language-features/plugin.md b/src/doc/unstable-book/src/language-features/plugin.md index 3835113152762..44308bdfba6c3 100644 --- a/src/doc/unstable-book/src/language-features/plugin.md +++ b/src/doc/unstable-book/src/language-features/plugin.md @@ -38,7 +38,7 @@ additional checks for code style, safety, etc. Now let's write a plugin [`lint-plugin-test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/ui-fulldeps/auxiliary/lint-plugin-test.rs) that warns about any item named `lintme`. -```rust,ignore +```rust,ignore (requires-stage-2) #![feature(plugin_registrar)] #![feature(box_syntax, rustc_private)] @@ -77,7 +77,7 @@ pub fn plugin_registrar(reg: &mut Registry) { Then code like -```rust,ignore +```rust,ignore (requires-plugin) #![feature(plugin)] #![plugin(lint_plugin_test)] diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md index 1d9409ee9e438..c67b806f06af4 100644 --- a/src/doc/unstable-book/src/language-features/rustc-attrs.md +++ b/src/doc/unstable-book/src/language-features/rustc-attrs.md @@ -18,7 +18,7 @@ Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`, ## Examples -```rust,ignore +```rust,compile_fail #![feature(rustc_attrs)] #[rustc_layout(abi, size)] diff --git a/src/doc/unstable-book/src/language-features/unboxed-closures.md b/src/doc/unstable-book/src/language-features/unboxed-closures.md index 71003fba00ba2..e4113d72d0914 100644 --- a/src/doc/unstable-book/src/language-features/unboxed-closures.md +++ b/src/doc/unstable-book/src/language-features/unboxed-closures.md @@ -9,7 +9,7 @@ See Also: [`fn_traits`](../library-features/fn-traits.md) ---- The `unboxed_closures` feature allows you to write functions using the `"rust-call"` ABI, -required for implementing the [`Fn*`] family of traits. `"rust-call"` functions must have +required for implementing the [`Fn*`] family of traits. `"rust-call"` functions must have exactly one (non self) argument, a tuple representing the argument list. [`Fn*`]: https://doc.rust-lang.org/std/ops/trait.Fn.html diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md index d716b1d51dcf7..d5b01a3d6168e 100644 --- a/src/doc/unstable-book/src/language-features/unsized-locals.md +++ b/src/doc/unstable-book/src/language-features/unsized-locals.md @@ -30,7 +30,7 @@ fn foo(_: dyn Any) {} The RFC still forbids the following unsized expressions: -```rust,ignore +```rust,compile_fail #![feature(unsized_locals)] use std::any::Any; @@ -124,7 +124,7 @@ One of the objectives of this feature is to allow `Box`. The RFC also describes an extension to the array literal syntax: `[e; dyn n]`. In the syntax, `n` isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of `[T]`, instead of `[T; n]`. -```rust,ignore +```rust,ignore (not-yet-implemented) #![feature(unsized_locals)] fn mergesort(a: &mut [T]) { diff --git a/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md b/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md index 731d2acbfdd5a..310c8d962948a 100644 --- a/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md +++ b/src/doc/unstable-book/src/language-features/unsized-tuple-coercion.md @@ -8,7 +8,7 @@ The tracking issue for this feature is: [#42877] This is a part of [RFC0401]. According to the RFC, there should be an implementation like this: -```rust,ignore +```rust,ignore (partial-example) impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized {} ``` diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index ccdd862869961..c0e23b834d150 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -405,7 +405,7 @@ When required, options are specified as the final argument. The following ABNF specifies the general syntax: -```ignore +```text dir_spec := "in" / "out" / "lateout" / "inout" / "inlateout" reg_spec := / "" operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_" diff --git a/src/doc/unstable-book/src/library-features/concat-idents.md b/src/doc/unstable-book/src/library-features/concat-idents.md index ecfd34a22e5cc..73f6cfa21787e 100644 --- a/src/doc/unstable-book/src/library-features/concat-idents.md +++ b/src/doc/unstable-book/src/library-features/concat-idents.md @@ -19,4 +19,4 @@ fn main() { let f = concat_idents!(foo, bar); assert_eq!(f(), 23); } -``` \ No newline at end of file +``` diff --git a/src/doc/unstable-book/src/library-features/global-asm.md b/src/doc/unstable-book/src/library-features/global-asm.md index bc55fe80fa64c..c5ff68ec7d39a 100644 --- a/src/doc/unstable-book/src/library-features/global-asm.md +++ b/src/doc/unstable-book/src/library-features/global-asm.md @@ -24,15 +24,15 @@ conventions of the assembler in your toolchain. A simple usage looks like this: -```rust,ignore +```rust,ignore (requires-external-file) # #![feature(global_asm)] -# you also need relevant target_arch cfgs +# // you also need relevant target_arch cfgs global_asm!(include_str!("something_neato.s")); ``` And a more complicated usage looks like this: -```rust,ignore +```rust,no_run # #![feature(global_asm)] # #![cfg(any(target_arch = "x86", target_arch = "x86_64"))] diff --git a/src/doc/unstable-book/src/library-features/llvm-asm.md b/src/doc/unstable-book/src/library-features/llvm-asm.md index a2f029db29165..07fc16261d820 100644 --- a/src/doc/unstable-book/src/library-features/llvm-asm.md +++ b/src/doc/unstable-book/src/library-features/llvm-asm.md @@ -10,7 +10,7 @@ For extremely low-level manipulations and performance reasons, one might wish to control the CPU directly. Rust supports using inline assembly to do this via the `llvm_asm!` macro. -```rust,ignore +```rust,ignore (pseudo-code) llvm_asm!(assembly template : output operands : input operands diff --git a/src/doc/unstable-book/src/library-features/test.md b/src/doc/unstable-book/src/library-features/test.md index 6b4a3a677db61..c99584e5fb397 100644 --- a/src/doc/unstable-book/src/library-features/test.md +++ b/src/doc/unstable-book/src/library-features/test.md @@ -9,7 +9,7 @@ most widely used part of the `test` crate are benchmark tests, which can test the performance of your code. Let's make our `src/lib.rs` look like this (comments elided): -```rust,ignore +```rust,no_run #![feature(test)] extern crate test; @@ -83,7 +83,7 @@ the benchmark is no longer benchmarking what one expects. For example, the compiler might recognize that some calculation has no external effects and remove it entirely. -```rust,ignore +```rust,no_run #![feature(test)] extern crate test; diff --git a/src/doc/unstable-book/src/library-features/try-trait.md b/src/doc/unstable-book/src/library-features/try-trait.md index 0c07329025bca..022640067bd11 100644 --- a/src/doc/unstable-book/src/library-features/try-trait.md +++ b/src/doc/unstable-book/src/library-features/try-trait.md @@ -16,7 +16,7 @@ macro on `Poll`, among other things. Here's an example implementation of the trait: -```rust,ignore +```rust,ignore (cannot-reimpl-Try) /// A distinct type to represent the `None` value of an `Option`. /// /// This enables using the `?` operator on `Option`; it's rarely useful alone. diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 74b61f1555c6f..d7951961223e4 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1331,16 +1331,16 @@ impl clean::GenericArg { } crate fn display_fn(f: impl FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Display { - WithFormatter(Cell::new(Some(f))) -} - -struct WithFormatter(Cell>); - -impl fmt::Display for WithFormatter -where - F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - (self.0.take()).unwrap()(f) + struct WithFormatter(Cell>); + + impl fmt::Display for WithFormatter + where + F: FnOnce(&mut fmt::Formatter<'_>) -> fmt::Result, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + (self.0.take()).unwrap()(f) + } } + + WithFormatter(Cell::new(Some(f))) } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index b2e5c8834b8ff..438a8d57cc222 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -162,8 +162,8 @@ impl From for ItemEnum { ForeignFunctionItem(f) => ItemEnum::FunctionItem(f.into()), TraitItem(t) => ItemEnum::TraitItem(t.into()), TraitAliasItem(t) => ItemEnum::TraitAliasItem(t.into()), - MethodItem(m, _) => ItemEnum::MethodItem(m.into()), - TyMethodItem(m) => ItemEnum::MethodItem(m.into()), + MethodItem(m, _) => ItemEnum::MethodItem(from_function_method(m, true)), + TyMethodItem(m) => ItemEnum::MethodItem(from_function_method(m, false)), ImplItem(i) => ItemEnum::ImplItem(i.into()), StaticItem(s) => ItemEnum::StaticItem(s.into()), ForeignStaticItem(s) => ItemEnum::StaticItem(s.into()), @@ -435,15 +435,13 @@ impl From for Impl { } } -impl From for Method { - fn from(function: clean::Function) -> Self { - let clean::Function { header, decl, generics, all_types: _, ret_types: _ } = function; - Method { - decl: decl.into(), - generics: generics.into(), - header: stringify_header(&header), - has_body: true, - } +crate fn from_function_method(function: clean::Function, has_body: bool) -> Method { + let clean::Function { header, decl, generics, all_types: _, ret_types: _ } = function; + Method { + decl: decl.into(), + generics: generics.into(), + header: stringify_header(&header), + has_body, } } diff --git a/src/test/rustdoc-json/traits/has_body.rs b/src/test/rustdoc-json/traits/has_body.rs new file mode 100644 index 0000000000000..44dacb1ee75bf --- /dev/null +++ b/src/test/rustdoc-json/traits/has_body.rs @@ -0,0 +1,21 @@ +// @has has_body.json "$.index[*][?(@.name=='Foo')]" +pub trait Foo { + // @has - "$.index[*][?(@.name=='no_self')].inner.has_body" false + fn no_self(); + // @has - "$.index[*][?(@.name=='move_self')].inner.has_body" false + fn move_self(self); + // @has - "$.index[*][?(@.name=='ref_self')].inner.has_body" false + fn ref_self(&self); + + // @has - "$.index[*][?(@.name=='no_self_def')].inner.has_body" true + fn no_self_def() {} + // @has - "$.index[*][?(@.name=='move_self_def')].inner.has_body" true + fn move_self_def(self) {} + // @has - "$.index[*][?(@.name=='ref_self_def')].inner.has_body" true + fn ref_self_def(&self) {} +} + +pub trait Bar: Clone { + // @has - "$.index[*][?(@.name=='method')].inner.has_body" false + fn method(&self, param: usize); +} diff --git a/src/test/ui-fulldeps/issue-15149.rs b/src/test/ui-fulldeps/issue-15149.rs index c80628aabc83f..c7ef5ad70a114 100644 --- a/src/test/ui-fulldeps/issue-15149.rs +++ b/src/test/ui-fulldeps/issue-15149.rs @@ -50,7 +50,7 @@ fn test() { .output().unwrap(); assert!(child_output.status.success(), - format!("child assertion failed\n child stdout:\n {}\n child stderr:\n {}", - str::from_utf8(&child_output.stdout).unwrap(), - str::from_utf8(&child_output.stderr).unwrap())); + "child assertion failed\n child stdout:\n {}\n child stderr:\n {}", + str::from_utf8(&child_output.stdout).unwrap(), + str::from_utf8(&child_output.stderr).unwrap()); } diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs index e9d66477d60a5..8ae8376ae4a6f 100644 --- a/src/test/ui/consts/const-eval/const_panic.rs +++ b/src/test/ui/consts/const-eval/const_panic.rs @@ -1,4 +1,5 @@ #![feature(const_panic)] +#![allow(non_fmt_panic)] #![crate_type = "lib"] const MSG: &str = "hello"; diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr index 713be5b662d54..74907a0b49518 100644 --- a/src/test/ui/consts/const-eval/const_panic.stderr +++ b/src/test/ui/consts/const-eval/const_panic.stderr @@ -1,10 +1,10 @@ error: any use of this value will cause an error - --> $DIR/const_panic.rs:6:15 + --> $DIR/const_panic.rs:7:15 | LL | const Z: () = std::panic!("cheese"); | --------------^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:6:15 + | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:7:15 | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! @@ -12,108 +12,108 @@ LL | const Z: () = std::panic!("cheese"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:10:16 + --> $DIR/const_panic.rs:11:16 | LL | const Z2: () = std::panic!(); | ---------------^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:10:16 + | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:11:16 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:14:15 + --> $DIR/const_panic.rs:15:15 | LL | const Y: () = std::unreachable!(); | --------------^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:14:15 + | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:15:15 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:18:15 + --> $DIR/const_panic.rs:19:15 | LL | const X: () = std::unimplemented!(); | --------------^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:18:15 + | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:19:15 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:22:15 + --> $DIR/const_panic.rs:23:15 | LL | const W: () = std::panic!(MSG); | --------------^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'hello', $DIR/const_panic.rs:22:15 + | the evaluated program panicked at 'hello', $DIR/const_panic.rs:23:15 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:26:20 + --> $DIR/const_panic.rs:27:20 | LL | const Z_CORE: () = core::panic!("cheese"); | -------------------^^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:26:20 + | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:27:20 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:30:21 + --> $DIR/const_panic.rs:31:21 | LL | const Z2_CORE: () = core::panic!(); | --------------------^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:30:21 + | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:31:21 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:34:20 + --> $DIR/const_panic.rs:35:20 | LL | const Y_CORE: () = core::unreachable!(); | -------------------^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:34:20 + | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:35:20 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:38:20 + --> $DIR/const_panic.rs:39:20 | LL | const X_CORE: () = core::unimplemented!(); | -------------------^^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:38:20 + | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:39:20 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: any use of this value will cause an error - --> $DIR/const_panic.rs:42:20 + --> $DIR/const_panic.rs:43:20 | LL | const W_CORE: () = core::panic!(MSG); | -------------------^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'hello', $DIR/const_panic.rs:42:20 + | the evaluated program panicked at 'hello', $DIR/const_panic.rs:43:20 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 diff --git a/src/test/ui/drop/dynamic-drop-async.rs b/src/test/ui/drop/dynamic-drop-async.rs index a952fe8e76e81..cb6d58a23d936 100644 --- a/src/test/ui/drop/dynamic-drop-async.rs +++ b/src/test/ui/drop/dynamic-drop-async.rs @@ -82,7 +82,7 @@ impl Allocator { self.cur_ops.set(self.cur_ops.get() + 1); if self.cur_ops.get() == self.failing_op { - panic!(InjectedFailure); + panic::panic_any(InjectedFailure); } } } diff --git a/src/test/ui/drop/dynamic-drop.rs b/src/test/ui/drop/dynamic-drop.rs index ddccee20e12a6..e28bedb982dd9 100644 --- a/src/test/ui/drop/dynamic-drop.rs +++ b/src/test/ui/drop/dynamic-drop.rs @@ -46,7 +46,7 @@ impl Allocator { self.cur_ops.set(self.cur_ops.get() + 1); if self.cur_ops.get() == self.failing_op { - panic!(InjectedFailure); + panic::panic_any(InjectedFailure); } let mut data = self.data.borrow_mut(); @@ -67,7 +67,7 @@ impl<'a> Drop for Ptr<'a> { self.1.cur_ops.set(self.1.cur_ops.get() + 1); if self.1.cur_ops.get() == self.1.failing_op { - panic!(InjectedFailure); + panic::panic_any(InjectedFailure); } } } diff --git a/src/test/ui/fmt/format-args-capture.rs b/src/test/ui/fmt/format-args-capture.rs index 4e3fa9a3c589a..d5886a13558c6 100644 --- a/src/test/ui/fmt/format-args-capture.rs +++ b/src/test/ui/fmt/format-args-capture.rs @@ -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(); diff --git a/src/test/ui/lint/forbid-group-group-1.rs b/src/test/ui/lint/forbid-group-group-1.rs new file mode 100644 index 0000000000000..80f7db4e56036 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-1.rs @@ -0,0 +1,13 @@ +// Check what happens when we forbid a smaller group but +// then allow a superset of that group. + +#![forbid(nonstandard_style)] + +// FIXME: Arguably this should be an error, but the WARNINGS group is +// treated in a very special (and rather ad-hoc) way and +// it fails to trigger. +#[allow(warnings)] +fn main() { + let A: (); + //~^ ERROR should have a snake case name +} diff --git a/src/test/ui/lint/forbid-group-group-1.stderr b/src/test/ui/lint/forbid-group-group-1.stderr new file mode 100644 index 0000000000000..fd425e5f74e6f --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-1.stderr @@ -0,0 +1,15 @@ +error: variable `A` should have a snake case name + --> $DIR/forbid-group-group-1.rs:11:9 + | +LL | let A: (); + | ^ help: convert the identifier to snake case: `a` + | +note: the lint level is defined here + --> $DIR/forbid-group-group-1.rs:4:11 + | +LL | #![forbid(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ + = note: `#[forbid(non_snake_case)]` implied by `#[forbid(nonstandard_style)]` + +error: aborting due to previous error + diff --git a/src/test/ui/lint/forbid-group-group-2.rs b/src/test/ui/lint/forbid-group-group-2.rs new file mode 100644 index 0000000000000..b12fd72da7494 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-2.rs @@ -0,0 +1,26 @@ +// Check what happens when we forbid a bigger group but +// then deny a subset of that group. + +#![forbid(warnings)] +#![deny(forbidden_lint_groups)] + +#[allow(nonstandard_style)] +//~^ ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +//~| ERROR incompatible with previous +//~| WARNING previously accepted by the compiler +fn main() {} diff --git a/src/test/ui/lint/forbid-group-group-2.stderr b/src/test/ui/lint/forbid-group-group-2.stderr new file mode 100644 index 0000000000000..214e949c11a74 --- /dev/null +++ b/src/test/ui/lint/forbid-group-group-2.stderr @@ -0,0 +1,115 @@ +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | +note: the lint level is defined here + --> $DIR/forbid-group-group-2.rs:5:9 + | +LL | #![deny(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: allow(nonstandard_style) incompatible with previous forbid + --> $DIR/forbid-group-group-2.rs:7:9 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +... +LL | #[allow(nonstandard_style)] + | ^^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/lint/forbid-group-member.rs b/src/test/ui/lint/forbid-group-member.rs new file mode 100644 index 0000000000000..6f1b2e9f66812 --- /dev/null +++ b/src/test/ui/lint/forbid-group-member.rs @@ -0,0 +1,19 @@ +// Check what happens when we forbid a group but +// then allow a member of that group. +// +// check-pass + +#![forbid(unused)] + +#[allow(unused_variables)] +//~^ WARNING incompatible with previous forbid +//~| WARNING previously accepted +//~| WARNING incompatible with previous forbid +//~| WARNING previously accepted +//~| WARNING incompatible with previous forbid +//~| WARNING previously accepted +//~| WARNING incompatible with previous forbid +//~| WARNING previously accepted +fn main() { + let a: (); +} diff --git a/src/test/ui/lint/forbid-group-member.stderr b/src/test/ui/lint/forbid-group-member.stderr new file mode 100644 index 0000000000000..c818d7ff60605 --- /dev/null +++ b/src/test/ui/lint/forbid-group-member.stderr @@ -0,0 +1,51 @@ +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = note: `#[warn(forbidden_lint_groups)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: allow(unused_variables) incompatible with previous forbid + --> $DIR/forbid-group-member.rs:8:9 + | +LL | #![forbid(unused)] + | ------ `forbid` level set here +LL | +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: 4 warnings emitted + diff --git a/src/test/ui/lint/forbid-member-group.rs b/src/test/ui/lint/forbid-member-group.rs new file mode 100644 index 0000000000000..3279029a9cbc3 --- /dev/null +++ b/src/test/ui/lint/forbid-member-group.rs @@ -0,0 +1,12 @@ +// Check what happens when we forbid a member of +// a group but then allow the group. + +#![forbid(unused_variables)] + +#[allow(unused)] +//~^ ERROR incompatible with previous forbid +//~| ERROR incompatible with previous forbid +//~| ERROR incompatible with previous forbid +fn main() { + let a: (); +} diff --git a/src/test/ui/lint/forbid-member-group.stderr b/src/test/ui/lint/forbid-member-group.stderr new file mode 100644 index 0000000000000..1d8ab4d5edb0c --- /dev/null +++ b/src/test/ui/lint/forbid-member-group.stderr @@ -0,0 +1,30 @@ +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/forbid-member-group.rs:6:9 + | +LL | #![forbid(unused_variables)] + | ---------------- `forbid` level set here +LL | +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/forbid-member-group.rs:6:9 + | +LL | #![forbid(unused_variables)] + | ---------------- `forbid` level set here +LL | +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + +error[E0453]: allow(unused) incompatible with previous forbid + --> $DIR/forbid-member-group.rs:6:9 + | +LL | #![forbid(unused_variables)] + | ---------------- `forbid` level set here +LL | +LL | #[allow(unused)] + | ^^^^^^ overruled by previous forbid + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs index f725304cf29d4..05d7d924c8fab 100644 --- a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs +++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.rs @@ -14,14 +14,17 @@ // compile-flags: -Z deduplicate-diagnostics=yes +#![forbid(forbidden_lint_groups)] + fn forbid_first(num: i32) -> i32 { #![forbid(unused)] #![deny(unused)] //~^ ERROR: deny(unused) incompatible with previous forbid + //~| WARNING being phased out + //~| ERROR: deny(unused) incompatible with previous forbid + //~| WARNING being phased out #![warn(unused)] - //~^ ERROR: warn(unused) incompatible with previous forbid #![allow(unused)] - //~^ ERROR: allow(unused) incompatible with previous forbid num * num } diff --git a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr index 9f107411c102a..475410cecffa3 100644 --- a/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr +++ b/src/test/ui/lint/issue-70819-dont-override-forbid-in-same-scope.stderr @@ -1,29 +1,29 @@ -error[E0453]: deny(unused) incompatible with previous forbid - --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:19:13 +error: deny(unused) incompatible with previous forbid + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13 | LL | #![forbid(unused)] | ------ `forbid` level set here LL | #![deny(unused)] | ^^^^^^ overruled by previous forbid + | +note: the lint level is defined here + --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:17:11 + | +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 -error[E0453]: warn(unused) incompatible with previous forbid +error: deny(unused) incompatible with previous forbid --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:21:13 | LL | #![forbid(unused)] | ------ `forbid` level set here -... -LL | #![warn(unused)] +LL | #![deny(unused)] | ^^^^^^ overruled by previous forbid - -error[E0453]: allow(unused) incompatible with previous forbid - --> $DIR/issue-70819-dont-override-forbid-in-same-scope.rs:23:14 | -LL | #![forbid(unused)] - | ------ `forbid` level set here -... -LL | #![allow(unused)] - | ^^^^^^ overruled by previous forbid + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/lint/issue-80988.rs b/src/test/ui/lint/issue-80988.rs new file mode 100644 index 0000000000000..16a041928db73 --- /dev/null +++ b/src/test/ui/lint/issue-80988.rs @@ -0,0 +1,16 @@ +// Regression test for #80988 +// +// check-pass + +#![forbid(warnings)] + +#[deny(warnings)] +//~^ WARNING incompatible with previous forbid +//~| WARNING being phased out +//~| WARNING incompatible with previous forbid +//~| WARNING being phased out +//~| WARNING incompatible with previous forbid +//~| WARNING being phased out +//~| WARNING incompatible with previous forbid +//~| WARNING being phased out +fn main() {} diff --git a/src/test/ui/lint/issue-80988.stderr b/src/test/ui/lint/issue-80988.stderr new file mode 100644 index 0000000000000..4cae11f97c0fb --- /dev/null +++ b/src/test/ui/lint/issue-80988.stderr @@ -0,0 +1,51 @@ +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = note: `#[warn(forbidden_lint_groups)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: deny(warnings) incompatible with previous forbid + --> $DIR/issue-80988.rs:7:8 + | +LL | #![forbid(warnings)] + | -------- `forbid` level set here +LL | +LL | #[deny(warnings)] + | ^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +warning: 4 warnings emitted + diff --git a/src/test/ui/lint/issue-81218.rs b/src/test/ui/lint/issue-81218.rs new file mode 100644 index 0000000000000..f02aa9040ebc5 --- /dev/null +++ b/src/test/ui/lint/issue-81218.rs @@ -0,0 +1,14 @@ +// Regression test for #81218 +// +// check-pass + +#![forbid(warnings)] + +#[allow(unused_variables)] +fn main() { + // We want to ensure that you don't get an error + // here. The idea is that a derive might generate + // code that would otherwise trigger the "unused variables" + // lint, but it is meant to be suppressed. + let x: (); +} diff --git a/src/test/ui/lint/outer-forbid.rs b/src/test/ui/lint/outer-forbid.rs index d45848bf706f3..486ec3c46804f 100644 --- a/src/test/ui/lint/outer-forbid.rs +++ b/src/test/ui/lint/outer-forbid.rs @@ -15,11 +15,16 @@ // compile-flags: -Z deduplicate-diagnostics=yes #![forbid(unused, non_snake_case)] +#![forbid(forbidden_lint_groups)] #[allow(unused_variables)] //~ ERROR incompatible with previous +//~^ ERROR incompatible with previous +//~| WARNING this was previously accepted by the compiler +//~| WARNING this was previously accepted by the compiler fn foo() {} #[allow(unused)] //~ ERROR incompatible with previous +//~^ WARNING this was previously accepted by the compiler fn bar() {} #[allow(nonstandard_style)] //~ ERROR incompatible with previous diff --git a/src/test/ui/lint/outer-forbid.stderr b/src/test/ui/lint/outer-forbid.stderr index c012c20697e16..d69157a8bb3ad 100644 --- a/src/test/ui/lint/outer-forbid.stderr +++ b/src/test/ui/lint/outer-forbid.stderr @@ -1,23 +1,34 @@ -error[E0453]: allow(unused_variables) incompatible with previous forbid - --> $DIR/outer-forbid.rs:19:9 +error: allow(unused_variables) incompatible with previous forbid + --> $DIR/outer-forbid.rs:20:9 | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here -LL | +... LL | #[allow(unused_variables)] | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | +note: the lint level is defined here + --> $DIR/outer-forbid.rs:18:11 + | +LL | #![forbid(forbidden_lint_groups)] + | ^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 -error[E0453]: allow(unused) incompatible with previous forbid - --> $DIR/outer-forbid.rs:22:9 +error: allow(unused) incompatible with previous forbid + --> $DIR/outer-forbid.rs:26:9 | LL | #![forbid(unused, non_snake_case)] | ------ `forbid` level set here ... LL | #[allow(unused)] | ^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 error[E0453]: allow(nonstandard_style) incompatible with previous forbid - --> $DIR/outer-forbid.rs:25:9 + --> $DIR/outer-forbid.rs:30:9 | LL | #![forbid(unused, non_snake_case)] | -------------- `forbid` level set here @@ -25,6 +36,18 @@ LL | #![forbid(unused, non_snake_case)] LL | #[allow(nonstandard_style)] | ^^^^^^^^^^^^^^^^^ overruled by previous forbid -error: aborting due to 3 previous errors +error: allow(unused_variables) incompatible with previous forbid + --> $DIR/outer-forbid.rs:20:9 + | +LL | #![forbid(unused, non_snake_case)] + | ------ `forbid` level set here +... +LL | #[allow(unused_variables)] + | ^^^^^^^^^^^^^^^^ overruled by previous forbid + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #81670 + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0453`. diff --git a/src/test/ui/macros/assert-macro-owned.rs b/src/test/ui/macros/assert-macro-owned.rs index b50fe65c0150f..2846f2a1f8353 100644 --- a/src/test/ui/macros/assert-macro-owned.rs +++ b/src/test/ui/macros/assert-macro-owned.rs @@ -2,6 +2,8 @@ // error-pattern:panicked at 'test-assert-owned' // ignore-emscripten no processes +#![allow(non_fmt_panic)] + fn main() { assert!(false, "test-assert-owned".to_string()); } diff --git a/src/test/ui/macros/macro-comma-behavior-rpass.rs b/src/test/ui/macros/macro-comma-behavior-rpass.rs index c46274d59b658..fd2c590ae5fd6 100644 --- a/src/test/ui/macros/macro-comma-behavior-rpass.rs +++ b/src/test/ui/macros/macro-comma-behavior-rpass.rs @@ -57,7 +57,7 @@ fn writeln_1arg() { // // (Example: Issue #48042) #[test] -#[allow(panic_fmt)] +#[allow(non_fmt_panic)] fn to_format_or_not_to_format() { // ("{}" is the easiest string to test because if this gets // sent to format_args!, it'll simply fail to compile. diff --git a/src/test/ui/mir/mir_drop_order.rs b/src/test/ui/mir/mir_drop_order.rs index 2949437b1e4b6..22c804abf5cc8 100644 --- a/src/test/ui/mir/mir_drop_order.rs +++ b/src/test/ui/mir/mir_drop_order.rs @@ -38,7 +38,7 @@ fn main() { assert_eq!(get(), vec![0, 2, 3, 1]); let _ = std::panic::catch_unwind(|| { - (d(4), &d(5), d(6), &d(7), panic!(InjectedFailure)); + (d(4), &d(5), d(6), &d(7), panic::panic_any(InjectedFailure)); }); // here, the temporaries (5/7) live until the end of the diff --git a/src/test/ui/panic-brace.rs b/src/test/ui/non-fmt-panic.rs similarity index 70% rename from src/test/ui/panic-brace.rs rename to src/test/ui/non-fmt-panic.rs index 754dcc287d0f9..25c53316e1290 100644 --- a/src/test/ui/panic-brace.rs +++ b/src/test/ui/non-fmt-panic.rs @@ -13,19 +13,27 @@ fn main() { core::panic!("Hello {}"); //~ WARN panic message contains an unused formatting placeholder assert!(false, "{:03x} {test} bla"); //~^ WARN panic message contains unused formatting placeholders + assert!(false, S); + //~^ WARN panic message is not a string literal debug_assert!(false, "{{}} bla"); //~ WARN panic message contains braces - panic!(C); // No warning (yet) - panic!(S); // No warning (yet) + panic!(C); //~ WARN panic message is not a string literal + panic!(S); //~ WARN panic message is not a string literal + std::panic!(123); //~ WARN panic message is not a string literal + core::panic!(&*"abc"); //~ WARN panic message is not a string literal panic!(concat!("{", "}")); //~ WARN panic message contains an unused formatting placeholder panic!(concat!("{", "{")); //~ WARN panic message contains braces fancy_panic::fancy_panic!("test {} 123"); //~^ WARN panic message contains an unused formatting placeholder + fancy_panic::fancy_panic!(S); + //~^ WARN panic message is not a string literal + // Check that the lint only triggers for std::panic and core::panic, // not any panic macro: macro_rules! panic { ($e:expr) => (); } panic!("{}"); // OK + panic!(S); // OK } diff --git a/src/test/ui/panic-brace.stderr b/src/test/ui/non-fmt-panic.stderr similarity index 52% rename from src/test/ui/panic-brace.stderr rename to src/test/ui/non-fmt-panic.stderr index 93808891c3c37..45187c518c423 100644 --- a/src/test/ui/panic-brace.stderr +++ b/src/test/ui/non-fmt-panic.stderr @@ -1,35 +1,35 @@ warning: panic message contains a brace - --> $DIR/panic-brace.rs:11:29 + --> $DIR/non-fmt-panic.rs:11:29 | LL | panic!("here's a brace: {"); | ^ | - = note: `#[warn(panic_fmt)]` on by default - = note: this message is not used as a format string, but will be in a future Rust edition + = note: `#[warn(non_fmt_panic)]` on by default + = note: this message is not used as a format string, but will be in Rust 2021 help: add a "{}" format string to use the message literally | LL | panic!("{}", "here's a brace: {"); | ^^^^^ warning: panic message contains a brace - --> $DIR/panic-brace.rs:12:31 + --> $DIR/non-fmt-panic.rs:12:31 | LL | std::panic!("another one: }"); | ^ | - = note: this message is not used as a format string, but will be in a future Rust edition + = note: this message is not used as a format string, but will be in Rust 2021 help: add a "{}" format string to use the message literally | LL | std::panic!("{}", "another one: }"); | ^^^^^ warning: panic message contains an unused formatting placeholder - --> $DIR/panic-brace.rs:13:25 + --> $DIR/non-fmt-panic.rs:13:25 | LL | core::panic!("Hello {}"); | ^^ | - = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition + = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 help: add the missing argument | LL | core::panic!("Hello {}", ...); @@ -40,12 +40,12 @@ LL | core::panic!("{}", "Hello {}"); | ^^^^^ warning: panic message contains unused formatting placeholders - --> $DIR/panic-brace.rs:14:21 + --> $DIR/non-fmt-panic.rs:14:21 | LL | assert!(false, "{:03x} {test} bla"); | ^^^^^^ ^^^^^^ | - = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition + = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 help: add the missing arguments | LL | assert!(false, "{:03x} {test} bla", ...); @@ -55,25 +55,97 @@ help: or add a "{}" format string to use the message literally LL | assert!(false, "{}", "{:03x} {test} bla"); | ^^^^^ +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:16:20 + | +LL | assert!(false, S); + | ^ + | + = note: this is no longer accepted in Rust 2021 +help: add a "{}" format string to Display the message + | +LL | assert!(false, "{}", S); + | ^^^^^ + warning: panic message contains braces - --> $DIR/panic-brace.rs:16:27 + --> $DIR/non-fmt-panic.rs:18:27 | LL | debug_assert!(false, "{{}} bla"); | ^^^^ | - = note: this message is not used as a format string, but will be in a future Rust edition + = note: this message is not used as a format string, but will be in Rust 2021 help: add a "{}" format string to use the message literally | LL | debug_assert!(false, "{}", "{{}} bla"); | ^^^^^ +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:19:12 + | +LL | panic!(C); + | ^ + | + = note: this is no longer accepted in Rust 2021 +help: add a "{}" format string to Display the message + | +LL | panic!("{}", C); + | ^^^^^ +help: or use std::panic::panic_any instead + | +LL | std::panic::panic_any(C); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:20:12 + | +LL | panic!(S); + | ^ + | + = note: this is no longer accepted in Rust 2021 +help: add a "{}" format string to Display the message + | +LL | panic!("{}", S); + | ^^^^^ +help: or use std::panic::panic_any instead + | +LL | std::panic::panic_any(S); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:21:17 + | +LL | std::panic!(123); + | ^^^ + | + = note: this is no longer accepted in Rust 2021 +help: add a "{}" format string to Display the message + | +LL | std::panic!("{}", 123); + | ^^^^^ +help: or use std::panic::panic_any instead + | +LL | std::panic::panic_any(123); + | ^^^^^^^^^^^^^^^^^^^^^^ + +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:22:18 + | +LL | core::panic!(&*"abc"); + | ^^^^^^^ + | + = note: this is no longer accepted in Rust 2021 +help: add a "{}" format string to Display the message + | +LL | core::panic!("{}", &*"abc"); + | ^^^^^ + warning: panic message contains an unused formatting placeholder - --> $DIR/panic-brace.rs:19:12 + --> $DIR/non-fmt-panic.rs:23:12 | LL | panic!(concat!("{", "}")); | ^^^^^^^^^^^^^^^^^ | - = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition + = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 help: add the missing argument | LL | panic!(concat!("{", "}"), ...); @@ -84,24 +156,32 @@ LL | panic!("{}", concat!("{", "}")); | ^^^^^ warning: panic message contains braces - --> $DIR/panic-brace.rs:20:5 + --> $DIR/non-fmt-panic.rs:24:5 | LL | panic!(concat!("{", "{")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: this message is not used as a format string, but will be in a future Rust edition + = note: this message is not used as a format string, but will be in Rust 2021 help: add a "{}" format string to use the message literally | LL | panic!("{}", concat!("{", "{")); | ^^^^^ warning: panic message contains an unused formatting placeholder - --> $DIR/panic-brace.rs:22:37 + --> $DIR/non-fmt-panic.rs:26:37 | LL | fancy_panic::fancy_panic!("test {} 123"); | ^^ | - = note: this message is not used as a format string when given without arguments, but will be in a future Rust edition + = note: this message is not used as a format string when given without arguments, but will be in Rust 2021 + +warning: panic message is not a string literal + --> $DIR/non-fmt-panic.rs:29:31 + | +LL | fancy_panic::fancy_panic!(S); + | ^ + | + = note: this is no longer accepted in Rust 2021 -warning: 8 warnings emitted +warning: 14 warnings emitted diff --git a/src/test/ui/pattern/or-pattern-macro-pat.rs b/src/test/ui/or-patterns/macro-pat.rs similarity index 100% rename from src/test/ui/pattern/or-pattern-macro-pat.rs rename to src/test/ui/or-patterns/macro-pat.rs diff --git a/src/test/ui/panics/explicit-panic-msg.rs b/src/test/ui/panics/explicit-panic-msg.rs index 1789e2e62c8b2..bfcc12cd186bd 100644 --- a/src/test/ui/panics/explicit-panic-msg.rs +++ b/src/test/ui/panics/explicit-panic-msg.rs @@ -1,5 +1,6 @@ #![allow(unused_assignments)] #![allow(unused_variables)] +#![allow(non_fmt_panic)] // run-fail // error-pattern:wooooo diff --git a/src/test/ui/panics/panic-macro-any-wrapped.rs b/src/test/ui/panics/panic-macro-any-wrapped.rs index 80c87c6f32c4b..95ae6ffe8be02 100644 --- a/src/test/ui/panics/panic-macro-any-wrapped.rs +++ b/src/test/ui/panics/panic-macro-any-wrapped.rs @@ -2,6 +2,8 @@ // error-pattern:panicked at 'Box' // ignore-emscripten no processes +#![allow(non_fmt_panic)] + fn main() { panic!(Box::new(612_i64)); } diff --git a/src/test/ui/panics/panic-macro-any.rs b/src/test/ui/panics/panic-macro-any.rs index ffc7114c1f5f2..d2a7ba3713a51 100644 --- a/src/test/ui/panics/panic-macro-any.rs +++ b/src/test/ui/panics/panic-macro-any.rs @@ -3,6 +3,7 @@ // ignore-emscripten no processes #![feature(box_syntax)] +#![allow(non_fmt_panic)] fn main() { panic!(box 413 as Box); diff --git a/src/test/ui/panics/while-panic.rs b/src/test/ui/panics/while-panic.rs index 857f65a225228..3c6ee8fa3155e 100644 --- a/src/test/ui/panics/while-panic.rs +++ b/src/test/ui/panics/while-panic.rs @@ -5,7 +5,7 @@ // ignore-emscripten no processes fn main() { - panic!({ + panic!("{}", { while true { panic!("giraffe") } diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index a17c5996293e9..4ee423b383b0f 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -2183,7 +2183,7 @@ fn lint_expect_fun_call( span_replace_word, &format!("use of `{}` followed by a function call", name), "try this", - format!("unwrap_or_else({} {{ panic!({}) }})", closure_args, arg_root_snippet), + format!("unwrap_or_else({} {{ panic!(\"{{}}\", {}) }})", closure_args, arg_root_snippet), applicability, ); } diff --git a/src/tools/clippy/tests/missing-test-files.rs b/src/tools/clippy/tests/missing-test-files.rs index d87bb4be3c3f9..9cef7438d225c 100644 --- a/src/tools/clippy/tests/missing-test-files.rs +++ b/src/tools/clippy/tests/missing-test-files.rs @@ -9,14 +9,12 @@ fn test_missing_tests() { if !missing_files.is_empty() { assert!( false, - format!( - "Didn't see a test file for the following files:\n\n{}\n", - missing_files - .iter() - .map(|s| format!("\t{}", s)) - .collect::>() - .join("\n") - ) + "Didn't see a test file for the following files:\n\n{}\n", + missing_files + .iter() + .map(|s| format!("\t{}", s)) + .collect::>() + .join("\n") ); } } diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.rs b/src/tools/clippy/tests/ui/assertions_on_constants.rs index 60d721c2f2049..e989de6540456 100644 --- a/src/tools/clippy/tests/ui/assertions_on_constants.rs +++ b/src/tools/clippy/tests/ui/assertions_on_constants.rs @@ -1,3 +1,5 @@ +#![allow(non_fmt_panic)] + macro_rules! assert_const { ($len:expr) => { assert!($len > 0); diff --git a/src/tools/clippy/tests/ui/assertions_on_constants.stderr b/src/tools/clippy/tests/ui/assertions_on_constants.stderr index 8f09c8ce9d52a..c66fdf093f514 100644 --- a/src/tools/clippy/tests/ui/assertions_on_constants.stderr +++ b/src/tools/clippy/tests/ui/assertions_on_constants.stderr @@ -1,5 +1,5 @@ error: `assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:9:5 + --> $DIR/assertions_on_constants.rs:11:5 | LL | assert!(true); | ^^^^^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | assert!(true); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false)` should probably be replaced - --> $DIR/assertions_on_constants.rs:10:5 + --> $DIR/assertions_on_constants.rs:12:5 | LL | assert!(false); | ^^^^^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | assert!(false); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:11:5 + --> $DIR/assertions_on_constants.rs:13:5 | LL | assert!(true, "true message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | assert!(true, "true message"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false, "false message")` should probably be replaced - --> $DIR/assertions_on_constants.rs:12:5 + --> $DIR/assertions_on_constants.rs:14:5 | LL | assert!(false, "false message"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | assert!(false, "false message"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false, msg.to_uppercase())` should probably be replaced - --> $DIR/assertions_on_constants.rs:15:5 + --> $DIR/assertions_on_constants.rs:17:5 | LL | assert!(false, msg.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | assert!(false, msg.to_uppercase()); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:18:5 + --> $DIR/assertions_on_constants.rs:20:5 | LL | assert!(B); | ^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | assert!(B); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false)` should probably be replaced - --> $DIR/assertions_on_constants.rs:21:5 + --> $DIR/assertions_on_constants.rs:23:5 | LL | assert!(C); | ^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | assert!(C); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `assert!(false, "C message")` should probably be replaced - --> $DIR/assertions_on_constants.rs:22:5 + --> $DIR/assertions_on_constants.rs:24:5 | LL | assert!(C, "C message"); | ^^^^^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | assert!(C, "C message"); = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: `debug_assert!(true)` will be optimized out by the compiler - --> $DIR/assertions_on_constants.rs:24:5 + --> $DIR/assertions_on_constants.rs:26:5 | LL | debug_assert!(true); | ^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/expect_fun_call.fixed b/src/tools/clippy/tests/ui/expect_fun_call.fixed index f3d8a941a92bc..a756d1cf50659 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.fixed +++ b/src/tools/clippy/tests/ui/expect_fun_call.fixed @@ -74,12 +74,12 @@ fn main() { "foo" } - Some("foo").unwrap_or_else(|| { panic!(get_string()) }); - Some("foo").unwrap_or_else(|| { panic!(get_string()) }); - Some("foo").unwrap_or_else(|| { panic!(get_string()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_string()) }); - Some("foo").unwrap_or_else(|| { panic!(get_static_str()) }); - Some("foo").unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_static_str()) }); + Some("foo").unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) }); } //Issue #3839 diff --git a/src/tools/clippy/tests/ui/expect_fun_call.stderr b/src/tools/clippy/tests/ui/expect_fun_call.stderr index a492e2df89d47..6dc796f5cee37 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.stderr +++ b/src/tools/clippy/tests/ui/expect_fun_call.stderr @@ -34,31 +34,31 @@ error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:77:21 | LL | Some("foo").expect(&get_string()); - | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:78:21 | LL | Some("foo").expect(get_string().as_ref()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:79:21 | LL | Some("foo").expect(get_string().as_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:81:21 | LL | Some("foo").expect(get_static_str()); - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_static_str()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_static_str()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:82:21 | LL | Some("foo").expect(get_non_static_str(&0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!(get_non_static_str(&0).to_string()) })` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| { panic!("{}", get_non_static_str(&0).to_string()) })` error: use of `expect` followed by a function call --> $DIR/expect_fun_call.rs:86:16 diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.rs b/src/tools/clippy/tests/ui/fallible_impl_from.rs index 679f4a7dc357d..5d5af4e463297 100644 --- a/src/tools/clippy/tests/ui/fallible_impl_from.rs +++ b/src/tools/clippy/tests/ui/fallible_impl_from.rs @@ -36,7 +36,7 @@ impl From> for Invalid { fn from(s: Option) -> Invalid { let s = s.unwrap(); if !s.is_empty() { - panic!(42); + panic!("42"); } else if s.parse::().unwrap() != 42 { panic!("{:?}", s); } diff --git a/src/tools/clippy/tests/ui/fallible_impl_from.stderr b/src/tools/clippy/tests/ui/fallible_impl_from.stderr index ab976b947b356..f787b30bdabc5 100644 --- a/src/tools/clippy/tests/ui/fallible_impl_from.stderr +++ b/src/tools/clippy/tests/ui/fallible_impl_from.stderr @@ -59,8 +59,8 @@ note: potential failure(s) LL | let s = s.unwrap(); | ^^^^^^^^^^ LL | if !s.is_empty() { -LL | panic!(42); - | ^^^^^^^^^^^ +LL | panic!("42"); + | ^^^^^^^^^^^^^ LL | } else if s.parse::().unwrap() != 42 { | ^^^^^^^^^^^^^^^^^^^^^^^^^ LL | panic!("{:?}", s); diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 6697fbd1be2de..9f68c55ec975c 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -18,6 +18,8 @@ use std::path::Path; +/// Error code markdown is restricted to 80 columns because they can be +/// displayed on the console with --example. const ERROR_CODE_COLS: usize = 80; const COLS: usize = 100; @@ -55,9 +57,9 @@ enum LIUState { /// Lines of this form are allowed to be overlength, because Markdown /// offers no way to split a line in the middle of a URL, and the lengths /// of URLs to external references are beyond our control. -fn line_is_url(columns: usize, line: &str) -> bool { - // more basic check for error_codes.rs, to avoid complexity in implementing two state machines - if columns == ERROR_CODE_COLS { +fn line_is_url(is_error_code: bool, columns: usize, line: &str) -> bool { + // more basic check for markdown, to avoid complexity in implementing two state machines + if is_error_code { return line.starts_with('[') && line.contains("]:") && line.contains("http"); } @@ -93,8 +95,13 @@ fn line_is_url(columns: usize, line: &str) -> bool { /// Returns `true` if `line` is allowed to be longer than the normal limit. /// Currently there is only one exception, for long URLs, but more /// may be added in the future. -fn long_line_is_ok(max_columns: usize, line: &str) -> bool { - if line_is_url(max_columns, line) { +fn long_line_is_ok(extension: &str, is_error_code: bool, max_columns: usize, line: &str) -> bool { + if extension != "md" || is_error_code { + if line_is_url(is_error_code, max_columns, line) { + return true; + } + } else if extension == "md" { + // non-error code markdown is allowed to be any length return true; } @@ -158,8 +165,36 @@ pub fn is_in(full_path: &Path, parent_folder_to_find: &str, folder_to_find: &str } } +fn skip_markdown_path(path: &Path) -> bool { + // These aren't ready for tidy. + const SKIP_MD: &[&str] = &[ + "src/doc/edition-guide", + "src/doc/embedded-book", + "src/doc/nomicon", + "src/doc/reference", + "src/doc/rust-by-example", + "src/doc/rustc-dev-guide", + ]; + SKIP_MD.iter().any(|p| path.ends_with(p)) +} + +fn is_unexplained_ignore(extension: &str, line: &str) -> bool { + if !line.ends_with("```ignore") && !line.ends_with("```rust,ignore") { + return false; + } + if extension == "md" && line.trim().starts_with("//") { + // Markdown examples may include doc comments with ignore inside a + // code block. + return false; + } + true +} + pub fn check(path: &Path, bad: &mut bool) { - super::walk(path, &mut super::filter_dirs, &mut |entry, contents| { + fn skip(path: &Path) -> bool { + super::filter_dirs(path) || skip_markdown_path(path) + } + super::walk(path, &mut skip, &mut |entry, contents| { let file = entry.path(); let filename = file.file_name().unwrap().to_string_lossy(); let extensions = [".rs", ".py", ".js", ".sh", ".c", ".cpp", ".h", ".md", ".css"]; @@ -176,13 +211,6 @@ pub fn check(path: &Path, bad: &mut bool) { a.ends_with("src/doc/book") }); - if filename.ends_with(".md") - && file.parent().unwrap().file_name().unwrap().to_string_lossy() != "error_codes" - { - // We don't want to check all ".md" files (almost of of them aren't compliant - // currently), just the long error code explanation ones. - return; - } if is_style_file && !is_in(file, "src", "librustdoc") { // We only check CSS files in rustdoc. return; @@ -192,11 +220,10 @@ pub fn check(path: &Path, bad: &mut bool) { tidy_error!(bad, "{}: empty file", file.display()); } - let max_columns = if filename == "error_codes.rs" || filename.ends_with(".md") { - ERROR_CODE_COLS - } else { - COLS - }; + let extension = file.extension().unwrap().to_string_lossy(); + let is_error_code = extension == "md" && is_in(file, "src", "error_codes"); + + let max_columns = if is_error_code { ERROR_CODE_COLS } else { COLS }; let can_contain = contents.contains("// ignore-tidy-") || contents.contains("# ignore-tidy-") @@ -227,7 +254,7 @@ pub fn check(path: &Path, bad: &mut bool) { }; if !under_rustfmt && line.chars().count() > max_columns - && !long_line_is_ok(max_columns, line) + && !long_line_is_ok(&extension, is_error_code, max_columns, line) { suppressible_tidy_err!( err, @@ -280,7 +307,7 @@ pub fn check(path: &Path, bad: &mut bool) { "copyright notices attributed to the Rust Project Developers are deprecated" ); } - if line.ends_with("```ignore") || line.ends_with("```rust,ignore") { + if is_unexplained_ignore(&extension, line) { err(UNEXPLAINED_IGNORE_DOCTEST_INFO); } if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {