about summary refs log tree commit diff
path: root/compiler/rustc_lint
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_lint')
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/internal.rs46
-rw-r--r--compiler/rustc_lint/src/levels.rs70
-rw-r--r--compiler/rustc_lint/src/lib.rs6
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs58
-rw-r--r--compiler/rustc_lint/src/panic_fmt.rs150
-rw-r--r--compiler/rustc_lint/src/redundant_semicolon.rs21
-rw-r--r--compiler/rustc_lint/src/types.rs2
-rw-r--r--compiler/rustc_lint/src/unused.rs2
11 files changed, 283 insertions, 79 deletions
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index 760a8e385d6..c56eb09b634 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -20,3 +20,4 @@ rustc_feature = { path = "../rustc_feature" }
 rustc_index = { path = "../rustc_index" }
 rustc_session = { path = "../rustc_session" }
 rustc_trait_selection = { path = "../rustc_trait_selection" }
+rustc_parse_format = { path = "../rustc_parse_format" }
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index c65cf65b1c7..676c85e4afd 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2345,7 +2345,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
         enum InitKind {
             Zeroed,
             Uninit,
-        };
+        }
 
         /// Information about why a type cannot be initialized this way.
         /// Contains an error message and optionally a span to point at.
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 4cfeb0d968b..16563d21ff1 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -19,7 +19,6 @@ use self::TargetLint::*;
 use crate::levels::LintLevelsBuilder;
 use crate::passes::{EarlyLintPassObject, LateLintPassObject};
 use rustc_ast as ast;
-use rustc_ast::util::lev_distance::find_best_match_for_name;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
 use rustc_errors::{add_elided_lifetime_in_path_suggestion, struct_span_err, Applicability};
@@ -37,6 +36,7 @@ use rustc_session::lint::BuiltinLintDiagnostics;
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
 use rustc_session::Session;
 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;
 
@@ -411,7 +411,7 @@ impl LintStore {
                         self.by_name.keys().map(|name| Symbol::intern(&name)).collect::<Vec<_>>();
 
                     let suggestion = find_best_match_for_name(
-                        symbols.iter(),
+                        &symbols,
                         Symbol::intern(&lint_name.to_lowercase()),
                         None,
                     );
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index c2d98b8e4ad..af5972c6c81 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -10,7 +10,7 @@ use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath,
 use rustc_middle::ty;
 use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
 use rustc_span::hygiene::{ExpnKind, MacroKind};
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{kw, sym, Ident, Symbol};
 
 declare_tool_lint! {
     pub rustc::DEFAULT_HASH_TYPES,
@@ -267,3 +267,47 @@ impl EarlyLintPass for LintPassImpl {
         }
     }
 }
+
+declare_tool_lint! {
+    pub rustc::EXISTING_DOC_KEYWORD,
+    Allow,
+    "Check that documented keywords in std and core actually exist",
+    report_in_external_macro: true
+}
+
+declare_lint_pass!(ExistingDocKeyword => [EXISTING_DOC_KEYWORD]);
+
+fn is_doc_keyword(s: Symbol) -> bool {
+    s <= kw::Union
+}
+
+impl<'tcx> LateLintPass<'tcx> for ExistingDocKeyword {
+    fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
+        for attr in item.attrs {
+            if !attr.has_name(sym::doc) {
+                continue;
+            }
+            if let Some(list) = attr.meta_item_list() {
+                for nested in list {
+                    if nested.has_name(sym::keyword) {
+                        let v = nested
+                            .value_str()
+                            .expect("#[doc(keyword = \"...\")] expected a value!");
+                        if is_doc_keyword(v) {
+                            return;
+                        }
+                        cx.struct_span_lint(EXISTING_DOC_KEYWORD, attr.span, |lint| {
+                            lint.build(&format!(
+                                "Found non-existing keyword `{}` used in \
+                                     `#[doc(keyword = \"...\")]`",
+                                v,
+                            ))
+                            .help("only existing keywords are allowed in core/std")
+                            .emit();
+                        });
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 02da85d25d5..3e22eba15aa 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -108,18 +108,32 @@ impl<'s> LintLevelsBuilder<'s> {
         id: LintId,
         (level, src): LevelSource,
     ) {
-        if let Some((old_level, old_src)) = specs.get(&id) {
-            if old_level == &Level::Forbid && level != Level::Forbid {
+        // Setting to a non-forbid level is an error if the lint previously had
+        // a forbid level. Note that this is not necessarily true even with a
+        // `#[forbid(..)]` attribute present, as that is overriden by `--cap-lints`.
+        //
+        // This means that this only errors if we're truly lowering the lint
+        // level from forbid.
+        if level != Level::Forbid {
+            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 in same scope",
+                    "{}({}) incompatible with previous forbid",
                     level.as_str(),
                     src.name(),
                 );
-                match *old_src {
-                    LintSource::Default => {}
+                diag_builder.span_label(src.span(), "overruled by previous forbid");
+                match old_src {
+                    LintSource::Default => {
+                        diag_builder.note(&format!(
+                            "`forbid` lint level is the default for {}",
+                            id.to_string()
+                        ));
+                    }
                     LintSource::Node(_, forbid_source_span, reason) => {
                         diag_builder.span_label(forbid_source_span, "`forbid` level set here");
                         if let Some(rationale) = reason {
@@ -131,6 +145,8 @@ impl<'s> LintLevelsBuilder<'s> {
                     }
                 }
                 diag_builder.emit();
+
+                // Retain the forbid lint level
                 return;
             }
         }
@@ -414,50 +430,6 @@ impl<'s> LintLevelsBuilder<'s> {
             }
         }
 
-        for (id, &(level, ref src)) in specs.iter() {
-            if level == Level::Forbid {
-                continue;
-            }
-            let forbid_src = match self.sets.get_lint_id_level(*id, self.cur, None) {
-                (Some(Level::Forbid), src) => src,
-                _ => continue,
-            };
-            let forbidden_lint_name = match forbid_src {
-                LintSource::Default => id.to_string(),
-                LintSource::Node(name, _, _) => name.to_string(),
-                LintSource::CommandLine(name, _) => name.to_string(),
-            };
-            let (lint_attr_name, lint_attr_span) = match *src {
-                LintSource::Node(name, span, _) => (name, span),
-                _ => continue,
-            };
-            let mut diag_builder = struct_span_err!(
-                self.sess,
-                lint_attr_span,
-                E0453,
-                "{}({}) overruled by outer forbid({})",
-                level.as_str(),
-                lint_attr_name,
-                forbidden_lint_name
-            );
-            diag_builder.span_label(lint_attr_span, "overruled by previous forbid");
-            match forbid_src {
-                LintSource::Default => {}
-                LintSource::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());
-                    }
-                }
-                LintSource::CommandLine(_, _) => {
-                    diag_builder.note("`forbid` lint level was set on command line");
-                }
-            }
-            diag_builder.emit();
-            // don't set a separate error for every lint in the group
-            break;
-        }
-
         let prev = self.cur;
         if !specs.is_empty() {
             self.cur = self.sets.list.len() as u32;
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index 24bfdad970a..80ef855c385 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -55,6 +55,7 @@ mod levels;
 mod methods;
 mod non_ascii_idents;
 mod nonstandard_style;
+mod panic_fmt;
 mod passes;
 mod redundant_semicolon;
 mod traits;
@@ -80,6 +81,7 @@ use internal::*;
 use methods::*;
 use non_ascii_idents::*;
 use nonstandard_style::*;
+use panic_fmt::PanicFmt;
 use redundant_semicolon::*;
 use traits::*;
 use types::*;
@@ -166,6 +168,7 @@ macro_rules! late_lint_passes {
                 ClashingExternDeclarations: ClashingExternDeclarations::new(),
                 DropTraitConstraints: DropTraitConstraints,
                 TemporaryCStringAsPtr: TemporaryCStringAsPtr,
+                PanicFmt: PanicFmt,
             ]
         );
     };
@@ -460,6 +463,8 @@ fn register_internals(store: &mut LintStore) {
     store.register_early_pass(|| box DefaultHashTypes::new());
     store.register_lints(&LintPassImpl::get_lints());
     store.register_early_pass(|| box LintPassImpl);
+    store.register_lints(&ExistingDocKeyword::get_lints());
+    store.register_late_pass(|| box ExistingDocKeyword);
     store.register_lints(&TyTyKind::get_lints());
     store.register_late_pass(|| box TyTyKind);
     store.register_group(
@@ -472,6 +477,7 @@ fn register_internals(store: &mut LintStore) {
             LintId::of(LINT_PASS_IMPL_WITHOUT_MACRO),
             LintId::of(TY_PASS_BY_REFERENCE),
             LintId::of(USAGE_OF_QUALIFIED_TY),
+            LintId::of(EXISTING_DOC_KEYWORD),
         ],
     );
 }
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index f117ce1f805..6d61b86f32e 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -94,9 +94,9 @@ fn to_camel_case(s: &str) -> String {
                 }
 
                 if new_word {
-                    camel_cased_component.push_str(&c.to_uppercase().to_string());
+                    camel_cased_component.extend(c.to_uppercase());
                 } else {
-                    camel_cased_component.push_str(&c.to_lowercase().to_string());
+                    camel_cased_component.extend(c.to_lowercase());
                 }
 
                 prev_is_lower_case = c.is_lowercase();
@@ -127,14 +127,20 @@ impl NonCamelCaseTypes {
         if !is_camel_case(name) {
             cx.struct_span_lint(NON_CAMEL_CASE_TYPES, ident.span, |lint| {
                 let msg = format!("{} `{}` should have an upper camel case name", sort, name);
-                lint.build(&msg)
-                    .span_suggestion(
+                let mut err = lint.build(&msg);
+                let cc = to_camel_case(name);
+                // We cannot provide meaningful suggestions
+                // if the characters are in the category of "Lowercase Letter".
+                if *name != cc {
+                    err.span_suggestion(
                         ident.span,
                         "convert the identifier to upper camel case",
                         to_camel_case(name),
                         Applicability::MaybeIncorrect,
-                    )
-                    .emit()
+                    );
+                }
+
+                err.emit();
             })
         }
     }
@@ -263,17 +269,21 @@ impl NonSnakeCase {
                 let sc = NonSnakeCase::to_snake_case(name);
                 let msg = format!("{} `{}` should have a snake case name", sort, name);
                 let mut err = lint.build(&msg);
-                // We have a valid span in almost all cases, but we don't have one when linting a crate
-                // name provided via the command line.
-                if !ident.span.is_dummy() {
-                    err.span_suggestion(
-                        ident.span,
-                        "convert the identifier to snake case",
-                        sc,
-                        Applicability::MaybeIncorrect,
-                    );
-                } else {
-                    err.help(&format!("convert the identifier to snake case: `{}`", sc));
+                // We cannot provide meaningful suggestions
+                // if the characters are in the category of "Uppercase Letter".
+                if *name != sc {
+                    // We have a valid span in almost all cases, but we don't have one when linting a crate
+                    // name provided via the command line.
+                    if !ident.span.is_dummy() {
+                        err.span_suggestion(
+                            ident.span,
+                            "convert the identifier to snake case",
+                            sc,
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        err.help(&format!("convert the identifier to snake case: `{}`", sc));
+                    }
                 }
 
                 err.emit();
@@ -441,14 +451,20 @@ impl NonUpperCaseGlobals {
         if name.chars().any(|c| c.is_lowercase()) {
             cx.struct_span_lint(NON_UPPER_CASE_GLOBALS, ident.span, |lint| {
                 let uc = NonSnakeCase::to_snake_case(&name).to_uppercase();
-                lint.build(&format!("{} `{}` should have an upper case name", sort, name))
-                    .span_suggestion(
+                let mut err =
+                    lint.build(&format!("{} `{}` should have an upper case name", sort, name));
+                // We cannot provide meaningful suggestions
+                // if the characters are in the category of "Lowercase Letter".
+                if *name != uc {
+                    err.span_suggestion(
                         ident.span,
                         "convert the identifier to upper case",
                         uc,
                         Applicability::MaybeIncorrect,
-                    )
-                    .emit();
+                    );
+                }
+
+                err.emit();
             })
         }
     }
diff --git a/compiler/rustc_lint/src/panic_fmt.rs b/compiler/rustc_lint/src/panic_fmt.rs
new file mode 100644
index 00000000000..0d2b20989b0
--- /dev/null
+++ b/compiler/rustc_lint/src/panic_fmt.rs
@@ -0,0 +1,150 @@
+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
+    ///
+    /// `panic!("{}")` panics with the message `"{}"`, as a `panic!()` invocation
+    /// with a single argument does not use `format_args!()`.
+    /// A future edition of Rust will interpret this string as format string,
+    /// which would break 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_macro, id)
+                    || cx.tcx.is_diagnostic_item(sym::core_panic_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 another level of macro expansion if this panic!()
+                    // was expanded from assert!() or debug_assert!().
+                    for &assert in &[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<Vec<_>> = snippet
+                            .filter(|s| s.starts_with('"') || s.starts_with("r#"))
+                            .map(|s| {
+                                s.char_indices()
+                                    .filter(|&(_, c)| c == '{' || c == '}')
+                                    .map(|(i, _)| {
+                                        fmt_span.from_inner(InnerSpan { start: i, end: i + 1 })
+                                    })
+                                    .collect()
+                            });
+                        let msg = match &brace_spans {
+                            Some(v) if v.len() == 1 => "panic message contains a brace",
+                            _ => "panic message contains braces",
+                        };
+                        cx.struct_span_lint(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/src/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs
index 84cc7b68d4c..428198cae89 100644
--- a/compiler/rustc_lint/src/redundant_semicolon.rs
+++ b/compiler/rustc_lint/src/redundant_semicolon.rs
@@ -28,25 +28,40 @@ declare_lint_pass!(RedundantSemicolons => [REDUNDANT_SEMICOLONS]);
 
 impl EarlyLintPass for RedundantSemicolons {
     fn check_block(&mut self, cx: &EarlyContext<'_>, block: &Block) {
+        let mut after_item_stmt = false;
         let mut seq = None;
         for stmt in block.stmts.iter() {
             match (&stmt.kind, &mut seq) {
                 (StmtKind::Empty, None) => seq = Some((stmt.span, false)),
                 (StmtKind::Empty, Some(seq)) => *seq = (seq.0.to(stmt.span), true),
-                (_, seq) => maybe_lint_redundant_semis(cx, seq),
+                (_, seq) => {
+                    maybe_lint_redundant_semis(cx, seq, after_item_stmt);
+                    after_item_stmt = matches!(stmt.kind, StmtKind::Item(_));
+                }
             }
         }
-        maybe_lint_redundant_semis(cx, &mut seq);
+        maybe_lint_redundant_semis(cx, &mut seq, after_item_stmt);
     }
 }
 
-fn maybe_lint_redundant_semis(cx: &EarlyContext<'_>, seq: &mut Option<(Span, bool)>) {
+fn maybe_lint_redundant_semis(
+    cx: &EarlyContext<'_>,
+    seq: &mut Option<(Span, bool)>,
+    after_item_stmt: bool,
+) {
     if let Some((span, multiple)) = seq.take() {
         // FIXME: Find a better way of ignoring the trailing
         // semicolon from macro expansion
         if span == rustc_span::DUMMY_SP {
             return;
         }
+
+        // FIXME: Lint on semicolons after item statements
+        // once doing so doesn't break bootstrapping
+        if after_item_stmt {
+            return;
+        }
+
         cx.struct_span_lint(REDUNDANT_SEMICOLONS, span, |lint| {
             let (msg, rem) = if multiple {
                 ("unnecessary trailing semicolons", "remove these semicolons")
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 38c71e6e925..9ad9d53cd0d 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -1131,7 +1131,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
     fn check_for_opaque_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool {
         struct ProhibitOpaqueTypes<'a, 'tcx> {
             cx: &'a LateContext<'tcx>,
-        };
+        }
 
         impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> {
             type BreakTy = Ty<'tcx>;
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 4bbc180b226..2a5ad5e6c98 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -1152,7 +1152,7 @@ declare_lint! {
     /// ```rust
     /// #![feature(box_syntax)]
     /// fn main() {
-    ///     let a = (box [1,2,3]).len();
+    ///     let a = (box [1, 2, 3]).len();
     /// }
     /// ```
     ///