]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #50763 - KyleStach1678:unused-loop-label, r=petrochenkov
authorbors <bors@rust-lang.org>
Sat, 19 May 2018 14:52:30 +0000 (14:52 +0000)
committerbors <bors@rust-lang.org>
Sat, 19 May 2018 14:52:30 +0000 (14:52 +0000)
Add lint checks for unused loop labels

Previously no warning was generated when a loop label was written out but never used (i.e. in a `break` or `continue` statement):
```rust
fn main() {
    'unused_label: loop {}
}
```
would compile without complaint.

This fix introduces `-W unused_loop_label`, which generates the following warning message for the above snippet:
```
warning: unused loop label
 --> main.rs:2:5
  |
2 |     'unused_label: loop {}
  |     ^^^^^^^^^^^^^
  |
  = note: #[warn(unused_loop_label)] on by default
```

Fixes: #50751.
1  2 
src/librustc/lint/builtin.rs
src/librustc_lint/lib.rs
src/librustc_resolve/lib.rs

index e5b8e5f0eb9a89043883872bf16acf42b2721713,79b4ec61bd081ba5eba79fcd4d3eb2094570f969..ac2fa8515bc1d1a836231592e63aea784f379be4
@@@ -176,6 -176,12 +176,6 @@@ declare_lint! 
       not named `mod.rs`"
  }
  
 -declare_lint! {
 -    pub LEGACY_IMPORTS,
 -    Deny,
 -    "detects names that resolve to ambiguous glob imports with RFC 1560"
 -}
 -
  declare_lint! {
      pub LEGACY_CONSTRUCTOR_VISIBILITY,
      Deny,
@@@ -273,6 -279,12 +273,12 @@@ declare_lint! 
      "detects name collision with an existing but unstable method"
  }
  
+ declare_lint! {
+     pub UNUSED_LABELS,
+     Allow,
+     "detects labels that are never used"
+ }
  /// Does nothing as a lint pass, but registers some `Lint`s
  /// which are used by other parts of the compiler.
  #[derive(Copy, Clone)]
@@@ -308,6 -320,7 +314,6 @@@ impl LintPass for HardwiredLints 
              SAFE_PACKED_BORROWS,
              PATTERNS_IN_FNS_WITHOUT_BODY,
              LEGACY_DIRECTORY_OWNERSHIP,
 -            LEGACY_IMPORTS,
              LEGACY_CONSTRUCTOR_VISIBILITY,
              MISSING_FRAGMENT_SPECIFIER,
              PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES,
              UNUSED_MUT,
              SINGLE_USE_LIFETIME,
              UNUSED_LIFETIME,
+             UNUSED_LABELS,
              TYVAR_BEHIND_RAW_POINTER,
              ELIDED_LIFETIME_IN_PATH,
              BARE_TRAIT_OBJECT,
diff --combined src/librustc_lint/lib.rs
index cf1348bfbfb6444614a76e6f67eefc593db21fc2,69825027b052bc77ed5fb17dabaf37915720e9c7..cfd5cf5a0f98c7a83565a0b4038ff69acc132979
@@@ -177,6 -177,7 +177,7 @@@ pub fn register_builtins(store: &mut li
                      UNUSED_DOC_COMMENT,
                      UNUSED_EXTERN_CRATES,
                      UNUSED_FEATURES,
+                     UNUSED_LABELS,
                      UNUSED_PARENS);
  
      add_lint_group!(sess,
              reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
              edition: None,
          },
 -        FutureIncompatibleInfo {
 -            id: LintId::of(LEGACY_IMPORTS),
 -            reference: "issue #38260 <https://github.com/rust-lang/rust/issues/38260>",
 -            edition: None,
 -        },
          FutureIncompatibleInfo {
              id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
              reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
          "converted into hard error, see https://github.com/rust-lang/rust/issues/36892");
      store.register_removed("extra_requirement_in_impl",
          "converted into hard error, see https://github.com/rust-lang/rust/issues/37166");
 +    store.register_removed("legacy_imports",
 +        "converted into hard error, see https://github.com/rust-lang/rust/issues/38260");
      store.register_removed("coerce_never",
          "converted into hard error, see https://github.com/rust-lang/rust/issues/48950");
      store.register_removed("resolve_trait_on_defaulted_unit",
index 94333c3a1d72e2c4c23e753b4233e125fba3e471,feb5af571e43505038bc9753a711ddda8f6f0793..bc5d50491ad6be021b585aa27d771d7b94d116a7
@@@ -1224,10 -1224,12 +1224,10 @@@ enum NameBindingKind<'a> 
          binding: &'a NameBinding<'a>,
          directive: &'a ImportDirective<'a>,
          used: Cell<bool>,
 -        legacy_self_import: bool,
      },
      Ambiguity {
          b1: &'a NameBinding<'a>,
          b2: &'a NameBinding<'a>,
 -        legacy: bool,
      }
  }
  
@@@ -1249,6 -1251,7 +1249,6 @@@ struct AmbiguityError<'a> 
      lexical: bool,
      b1: &'a NameBinding<'a>,
      b2: &'a NameBinding<'a>,
 -    legacy: bool,
  }
  
  impl<'a> NameBinding<'a> {
          match self.kind {
              NameBindingKind::Module(module) => Some(module),
              NameBindingKind::Import { binding, .. } => binding.module(),
 -            NameBindingKind::Ambiguity { legacy: true, b1, .. } => b1.module(),
              _ => None,
          }
      }
              NameBindingKind::Def(def) => def,
              NameBindingKind::Module(module) => module.def().unwrap(),
              NameBindingKind::Import { binding, .. } => binding.def(),
 -            NameBindingKind::Ambiguity { legacy: true, b1, .. } => b1.def(),
              NameBindingKind::Ambiguity { .. } => Def::Err,
          }
      }
@@@ -1468,6 -1473,10 +1468,10 @@@ pub struct Resolver<'a> 
      pub maybe_unused_trait_imports: NodeSet,
      pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,
  
+     /// A list of labels as of yet unused. Labels will be removed from this map when
+     /// they are used (in a `break` or `continue` statement)
+     pub unused_labels: FxHashMap<NodeId, Span>,
      /// privacy errors are delayed until the end in order to deduplicate them
      privacy_errors: Vec<PrivacyError<'a>>,
      /// ambiguity errors are delayed for deduplication
@@@ -1747,6 -1756,8 +1751,8 @@@ impl<'a> Resolver<'a> 
              maybe_unused_trait_imports: NodeSet(),
              maybe_unused_extern_crates: Vec::new(),
  
+             unused_labels: FxHashMap(),
              privacy_errors: Vec::new(),
              ambiguity_errors: Vec::new(),
              use_injections: Vec::new(),
      fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
                    -> bool /* true if an error was reported */ {
          match binding.kind {
 -            NameBindingKind::Import { directive, binding, ref used, legacy_self_import }
 +            NameBindingKind::Import { directive, binding, ref used }
                      if !used.get() => {
                  used.set(true);
                  directive.used.set(true);
 -                if legacy_self_import {
 -                    self.warn_legacy_self_import(directive);
 -                    return false;
 -                }
                  self.used_imports.insert((directive.id, ns));
                  self.add_to_glob_map(directive.id, ident);
                  self.record_use(ident, ns, binding, span)
              }
              NameBindingKind::Import { .. } => false,
 -            NameBindingKind::Ambiguity { b1, b2, legacy } => {
 +            NameBindingKind::Ambiguity { b1, b2 } => {
                  self.ambiguity_errors.push(AmbiguityError {
 -                    span: span, name: ident.name, lexical: false, b1: b1, b2: b2, legacy,
 +                    span, name: ident.name, lexical: false, b1, b2,
                  });
 -                if legacy {
 -                    self.record_use(ident, ns, b1, span);
 -                }
 -                !legacy
 +                true
              }
              _ => false
          }
          where F: FnOnce(&mut Resolver)
      {
          if let Some(label) = label {
+             self.unused_labels.insert(id, label.ident.span);
              let def = Def::Label(id);
              self.with_label_rib(|this| {
                  this.label_ribs.last_mut().unwrap().bindings.insert(label.ident, def);
                                        ResolutionError::UndeclaredLabel(&label.ident.name.as_str(),
                                                                         close_match));
                      }
-                     Some(def @ Def::Label(_)) => {
+                     Some(Def::Label(id)) => {
                          // Since this def is a label, it is never read.
-                         self.record_def(expr.id, PathResolution::new(def));
+                         self.record_def(expr.id, PathResolution::new(Def::Label(id)));
+                         self.unused_labels.remove(&id);
                      }
                      Some(_) => {
                          span_bug!(expr.span, "label wasn't mapped to a label def!");
          self.report_proc_macro_import(krate);
          let mut reported_spans = FxHashSet();
  
 -        for &AmbiguityError { span, name, b1, b2, lexical, legacy } in &self.ambiguity_errors {
 +        for &AmbiguityError { span, name, b1, b2, lexical } in &self.ambiguity_errors {
              if !reported_spans.insert(span) { continue }
              let participle = |binding: &NameBinding| {
                  if binding.is_import() { "imported" } else { "defined" }
                  format!("macro-expanded {} do not shadow when used in a macro invocation path",
                          if b1.is_import() { "imports" } else { "items" })
              };
 -            if legacy {
 -                let id = match b2.kind {
 -                    NameBindingKind::Import { directive, .. } => directive.id,
 -                    _ => unreachable!(),
 -                };
 -                let mut span = MultiSpan::from_span(span);
 -                span.push_span_label(b1.span, msg1);
 -                span.push_span_label(b2.span, msg2);
 -                let msg = format!("`{}` is ambiguous", name);
 -                self.session.buffer_lint(lint::builtin::LEGACY_IMPORTS, id, span, &msg);
 -            } else {
 -                let mut err =
 -                    struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
 -                err.span_note(b1.span, &msg1);
 -                match b2.def() {
 -                    Def::Macro(..) if b2.span == DUMMY_SP =>
 -                        err.note(&format!("`{}` is also a builtin macro", name)),
 -                    _ => err.span_note(b2.span, &msg2),
 -                };
 -                err.note(&note).emit();
 -            }
 +
 +            let mut err = struct_span_err!(self.session, span, E0659, "`{}` is ambiguous", name);
 +            err.span_note(b1.span, &msg1);
 +            match b2.def() {
 +                Def::Macro(..) if b2.span == DUMMY_SP =>
 +                    err.note(&format!("`{}` is also a builtin macro", name)),
 +                _ => err.span_note(b2.span, &msg2),
 +            };
 +            err.note(&note).emit();
          }
  
          for &PrivacyError(span, name, binding) in &self.privacy_errors {
          self.name_already_seen.insert(name, span);
      }
  
 -    fn warn_legacy_self_import(&self, directive: &'a ImportDirective<'a>) {
 -        let (id, span) = (directive.id, directive.span);
 -        let msg = "`self` no longer imports values";
 -        self.session.buffer_lint(lint::builtin::LEGACY_IMPORTS, id, span, msg);
 -    }
 -
      fn check_proc_macro_attrs(&mut self, attrs: &[ast::Attribute]) {
          if self.proc_macro_enabled { return; }