]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #41965 - Mark-Simulacrum:rollup, r=Mark-Simulacrum
authorbors <bors@rust-lang.org>
Sat, 13 May 2017 11:35:59 +0000 (11:35 +0000)
committerbors <bors@rust-lang.org>
Sat, 13 May 2017 11:35:59 +0000 (11:35 +0000)
Rollup of 15 pull requests

- Successful merges: #41820, #41860, #41876, #41896, #41912, #41916, #41918, #41921, #41923, #41934, #41935, #41940, #41942, #41943, #41951
- Failed merges:

1  2 
src/librustc_errors/lib.rs
src/librustc_resolve/lib.rs
src/librustc_trans/lib.rs

index 0f2e1669a47ad5502cb22d4ce7f2b422c432463a,e1ec23479ab8a7ef84249db60c626b04a116787c..7a561e3a9703f82623fa80f28de306a8e9a9882b
@@@ -9,6 -9,7 +9,6 @@@
  // except according to those terms.
  
  #![crate_name = "rustc_errors"]
 -#![unstable(feature = "rustc_private", issue = "27812")]
  #![crate_type = "dylib"]
  #![crate_type = "rlib"]
  #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
  
  #![feature(custom_attribute)]
  #![allow(unused_attributes)]
 -#![feature(rustc_private)]
 -#![feature(staged_api)]
  #![feature(range_contains)]
  #![feature(libc)]
+ #![feature(conservative_impl_trait)]
  
 +#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
 +#![cfg_attr(stage0, feature(rustc_private))]
 +#![cfg_attr(stage0, feature(staged_api))]
 +
  extern crate term;
  extern crate libc;
  extern crate serialize as rustc_serialize;
@@@ -66,11 -66,35 +67,35 @@@ pub enum RenderSpan 
  
  #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
  pub struct CodeSuggestion {
-     pub msp: MultiSpan,
-     pub substitutes: Vec<String>,
+     /// Each substitute can have multiple variants due to multiple
+     /// applicable suggestions
+     ///
+     /// `foo.bar` might be replaced with `a.b` or `x.y` by replacing
+     /// `foo` and `bar` on their own:
+     ///
+     /// ```
+     /// vec![
+     ///     (0..3, vec!["a", "x"]),
+     ///     (4..7, vec!["b", "y"]),
+     /// ]
+     /// ```
+     ///
+     /// or by replacing the entire span:
+     ///
+     /// ```
+     /// vec![(0..7, vec!["a.b", "x.y"])]
+     /// ```
+     pub substitution_parts: Vec<Substitution>,
      pub msg: String,
  }
  
+ #[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
+ /// See the docs on `CodeSuggestion::substitutions`
+ pub struct Substitution {
+     pub span: Span,
+     pub substitutions: Vec<String>,
+ }
  pub trait CodeMapper {
      fn lookup_char_pos(&self, pos: BytePos) -> Loc;
      fn span_to_lines(&self, sp: Span) -> FileLinesResult;
  }
  
  impl CodeSuggestion {
-     /// Returns the assembled code suggestion.
-     pub fn splice_lines(&self, cm: &CodeMapper) -> String {
+     /// Returns the number of substitutions
+     fn substitutions(&self) -> usize {
+         self.substitution_parts[0].substitutions.len()
+     }
+     /// Returns the number of substitutions
+     pub fn substitution_spans<'a>(&'a self) -> impl Iterator<Item = Span> + 'a {
+         self.substitution_parts.iter().map(|sub| sub.span)
+     }
+     /// Returns the assembled code suggestions.
+     pub fn splice_lines(&self, cm: &CodeMapper) -> Vec<String> {
          use syntax_pos::{CharPos, Loc, Pos};
  
          fn push_trailing(buf: &mut String,
              }
          }
  
-         let mut primary_spans = self.msp.primary_spans().to_owned();
-         assert_eq!(primary_spans.len(), self.substitutes.len());
-         if primary_spans.is_empty() {
-             return format!("");
+         if self.substitution_parts.is_empty() {
+             return vec![String::new()];
          }
  
+         let mut primary_spans: Vec<_> = self.substitution_parts
+             .iter()
+             .map(|sub| (sub.span, &sub.substitutions))
+             .collect();
          // Assumption: all spans are in the same file, and all spans
          // are disjoint. Sort in ascending order.
-         primary_spans.sort_by_key(|sp| sp.lo);
+         primary_spans.sort_by_key(|sp| sp.0.lo);
  
          // Find the bounding span.
-         let lo = primary_spans.iter().map(|sp| sp.lo).min().unwrap();
-         let hi = primary_spans.iter().map(|sp| sp.hi).min().unwrap();
+         let lo = primary_spans.iter().map(|sp| sp.0.lo).min().unwrap();
+         let hi = primary_spans.iter().map(|sp| sp.0.hi).min().unwrap();
          let bounding_span = Span {
              lo: lo,
              hi: hi,
          prev_hi.col = CharPos::from_usize(0);
  
          let mut prev_line = fm.get_line(lines.lines[0].line_index);
-         let mut buf = String::new();
+         let mut bufs = vec![String::new(); self.substitutions()];
  
-         for (sp, substitute) in primary_spans.iter().zip(self.substitutes.iter()) {
+         for (sp, substitutes) in primary_spans {
              let cur_lo = cm.lookup_char_pos(sp.lo);
-             if prev_hi.line == cur_lo.line {
-                 push_trailing(&mut buf, prev_line, &prev_hi, Some(&cur_lo));
-             } else {
-                 push_trailing(&mut buf, prev_line, &prev_hi, None);
-                 // push lines between the previous and current span (if any)
-                 for idx in prev_hi.line..(cur_lo.line - 1) {
-                     if let Some(line) = fm.get_line(idx) {
-                         buf.push_str(line);
-                         buf.push('\n');
+             for (buf, substitute) in bufs.iter_mut().zip(substitutes) {
+                 if prev_hi.line == cur_lo.line {
+                     push_trailing(buf, prev_line, &prev_hi, Some(&cur_lo));
+                 } else {
+                     push_trailing(buf, prev_line, &prev_hi, None);
+                     // push lines between the previous and current span (if any)
+                     for idx in prev_hi.line..(cur_lo.line - 1) {
+                         if let Some(line) = fm.get_line(idx) {
+                             buf.push_str(line);
+                             buf.push('\n');
+                         }
+                     }
+                     if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
+                         buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
                      }
                  }
-                 if let Some(cur_line) = fm.get_line(cur_lo.line - 1) {
-                     buf.push_str(&cur_line[..cur_lo.col.to_usize()]);
-                 }
+                 buf.push_str(substitute);
              }
-             buf.push_str(substitute);
              prev_hi = cm.lookup_char_pos(sp.hi);
              prev_line = fm.get_line(prev_hi.line - 1);
          }
-         push_trailing(&mut buf, prev_line, &prev_hi, None);
-         // remove trailing newline
-         buf.pop();
-         buf
+         for buf in &mut bufs {
+             // if the replacement already ends with a newline, don't print the next line
+             if !buf.ends_with('\n') {
+                 push_trailing(buf, prev_line, &prev_hi, None);
+             }
+             // remove trailing newline
+             buf.pop();
+         }
+         bufs
      }
  }
  
index ee72aee042e91b0c232fa2b0af1d052561b872af,6054f46370e3257ccc98c95ed8f16d9e34206128..c4512cb38c4e24270b85ef4a5d8755801295bfbb
@@@ -9,6 -9,7 +9,6 @@@
  // except according to those terms.
  
  #![crate_name = "rustc_resolve"]
 -#![unstable(feature = "rustc_private", issue = "27812")]
  #![crate_type = "dylib"]
  #![crate_type = "rlib"]
  #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
  
  #![feature(associated_consts)]
  #![feature(rustc_diagnostic_macros)]
 -#![feature(rustc_private)]
 -#![feature(staged_api)]
 +
 +#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
 +#![cfg_attr(stage0, feature(rustc_private))]
 +#![cfg_attr(stage0, feature(staged_api))]
  
  #[macro_use]
  extern crate log;
@@@ -614,7 -613,7 +614,7 @@@ impl<'a, 'tcx> Visitor<'tcx> for Resolv
              self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
          } else if let TyKind::ImplicitSelf = ty.node {
              let self_ty = keywords::SelfType.ident();
-             let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
+             let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, true, ty.span)
                            .map_or(Def::Err, |d| d.def());
              self.record_def(ty.id, PathResolution::new(def));
          } else if let TyKind::Array(ref element, ref length) = ty.node {
@@@ -866,12 -865,18 +866,18 @@@ pub struct ModuleData<'a> 
      // access the children must be preceded with a
      // `populate_module_if_necessary` call.
      populated: Cell<bool>,
+     /// Span of the module itself. Used for error reporting.
+     span: Span,
  }
  
  pub type Module<'a> = &'a ModuleData<'a>;
  
  impl<'a> ModuleData<'a> {
-     fn new(parent: Option<Module<'a>>, kind: ModuleKind, normal_ancestor_id: DefId) -> Self {
+     fn new(parent: Option<Module<'a>>,
+            kind: ModuleKind,
+            normal_ancestor_id: DefId,
+            span: Span) -> Self {
          ModuleData {
              parent: parent,
              kind: kind,
              globs: RefCell::new((Vec::new())),
              traits: RefCell::new(None),
              populated: Cell::new(normal_ancestor_id.is_local()),
+             span: span,
          }
      }
  
@@@ -1261,11 -1267,11 +1268,11 @@@ impl<'a> hir::lowering::Resolver for Re
          let namespace = if is_value { ValueNS } else { TypeNS };
          let hir::Path { ref segments, span, ref mut def } = *path;
          let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect();
-         match self.resolve_path(&path, Some(namespace), Some(span)) {
+         match self.resolve_path(&path, Some(namespace), true, span) {
              PathResult::Module(module) => *def = module.def().unwrap(),
              PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 =>
                  *def = path_res.base_def(),
-             PathResult::NonModule(..) => match self.resolve_path(&path, None, Some(span)) {
+             PathResult::NonModule(..) => match self.resolve_path(&path, None, true, span) {
                  PathResult::Failed(msg, _) => {
                      resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
                  }
@@@ -1299,7 -1305,7 +1306,7 @@@ impl<'a> Resolver<'a> 
          let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name());
          let graph_root = arenas.alloc_module(ModuleData {
              no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"),
-             ..ModuleData::new(None, root_module_kind, root_def_id)
+             ..ModuleData::new(None, root_module_kind, root_def_id, krate.span)
          });
          let mut module_map = FxHashMap();
          module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
          self.crate_loader.postprocess(krate);
      }
  
-     fn new_module(&self, parent: Module<'a>, kind: ModuleKind, normal_ancestor_id: DefId)
-                   -> Module<'a> {
-         self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id))
+     fn new_module(
+         &self,
+         parent: Module<'a>,
+         kind: ModuleKind,
+         normal_ancestor_id: DefId,
+         span: Span,
+     ) -> Module<'a> {
+         self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id, span))
      }
  
      fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
      fn resolve_ident_in_lexical_scope(&mut self,
                                        mut ident: Ident,
                                        ns: Namespace,
-                                       record_used: Option<Span>)
+                                       record_used: bool,
+                                       path_span: Span)
                                        -> Option<LexicalScopeBinding<'a>> {
          if ns == TypeNS {
              ident = ident.unhygienize();
              if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
                  // The ident resolves to a type parameter or local variable.
                  return Some(LexicalScopeBinding::Def(
-                     self.adjust_local_def(ns, i, def, record_used)
+                     self.adjust_local_def(ns, i, def, record_used, path_span)
                  ));
              }
  
              if let ModuleRibKind(module) = self.ribs[ns][i].kind {
-                 let item = self.resolve_ident_in_module(module, ident, ns, false, record_used);
+                 let item = self.resolve_ident_in_module(module, ident, ns, false,
+                                                         record_used, path_span);
                  if let Ok(binding) = item {
                      // The ident resolves to an item.
                      return Some(LexicalScopeBinding::Item(binding));
                  if let ModuleKind::Block(..) = module.kind { // We can see through blocks
                  } else if !module.no_implicit_prelude {
                      return self.prelude.and_then(|prelude| {
-                         self.resolve_ident_in_module(prelude, ident, ns, false, None).ok()
+                         self.resolve_ident_in_module(prelude, ident, ns, false,
+                                                      false, path_span).ok()
                      }).map(LexicalScopeBinding::Item)
                  } else {
                      return None;
          None
      }
  
-     fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext) -> Module<'a> {
+     fn resolve_crate_var(&mut self, crate_var_ctxt: SyntaxContext, span: Span) -> Module<'a> {
          let mut ctxt_data = crate_var_ctxt.data();
          while ctxt_data.prev_ctxt != SyntaxContext::empty() {
              ctxt_data = ctxt_data.prev_ctxt.data();
          }
-         let module = self.macro_def_scope(ctxt_data.outer_mark);
+         let module = self.macro_def_scope(ctxt_data.outer_mark, span);
          if module.is_local() { self.graph_root } else { module }
      }
  
                  PatKind::Ident(bmode, ref ident, ref opt_pat) => {
                      // First try to resolve the identifier as some existing
                      // entity, then fall back to a fresh binding.
-                     let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS, None)
+                     let binding = self.resolve_ident_in_lexical_scope(ident.node, ValueNS,
+                                                                       false, pat.span)
                                        .and_then(LexicalScopeBinding::item);
                      let resolution = binding.map(NameBinding::def).and_then(|def| {
                          let always_binding = !pat_src.is_refutable() || opt_pat.is_some() ||
                      (format!(""), format!("the crate root"))
                  } else {
                      let mod_path = &path[..path.len() - 1];
-                     let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), None) {
+                     let mod_prefix = match this.resolve_path(mod_path, Some(TypeNS), false, span) {
                          PathResult::Module(module) => module.def(),
                          _ => None,
                      }.map_or(format!(""), |def| format!("{} ", def.kind_name()));
              let name = path.last().unwrap().name;
              let candidates = this.lookup_import_candidates(name, ns, is_expected);
              if !candidates.is_empty() {
+                 let mut module_span = this.current_module.span;
+                 module_span.hi = module_span.lo;
                  // Report import candidates as help and proceed searching for labels.
-                 show_candidates(&mut err, &candidates, def.is_some());
+                 show_candidates(&mut err, module_span, &candidates, def.is_some());
              } else if is_expected(Def::Enum(DefId::local(CRATE_DEF_INDEX))) {
                  let enum_candidates = this.lookup_import_candidates(name, ns, is_enum_variant);
                  let mut enum_candidates = enum_candidates.iter()
                      }
                  }
              }
-             if path.len() == 1 && this.self_type_is_available() {
+             if path.len() == 1 && this.self_type_is_available(span) {
                  if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) {
-                     let self_is_available = this.self_value_is_available(path[0].ctxt);
+                     let self_is_available = this.self_value_is_available(path[0].ctxt, span);
                      match candidate {
                          AssocSuggestion::Field => {
                              err.span_label(span, format!("did you mean `self.{}`?", path_str));
              let mut levenshtein_worked = false;
  
              // Try Levenshtein.
-             if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected) {
+             if let Some(candidate) = this.lookup_typo_candidate(path, ns, is_expected, span) {
                  err.span_label(ident_span, format!("did you mean `{}`?", candidate));
                  levenshtein_worked = true;
              }
          resolution
      }
  
-     fn self_type_is_available(&mut self) -> bool {
-         let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(), TypeNS, None);
+     fn self_type_is_available(&mut self, span: Span) -> bool {
+         let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(),
+                                                           TypeNS, false, span);
          if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
      }
  
-     fn self_value_is_available(&mut self, ctxt: SyntaxContext) -> bool {
+     fn self_value_is_available(&mut self, ctxt: SyntaxContext, span: Span) -> bool {
          let ident = Ident { name: keywords::SelfValue.name(), ctxt: ctxt };
-         let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None);
+         let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, false, span);
          if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
      }
  
              ));
          }
  
-         let result = match self.resolve_path(&path, Some(ns), Some(span)) {
+         let result = match self.resolve_path(&path, Some(ns), true, span) {
              PathResult::NonModule(path_res) => path_res,
              PathResult::Module(module) if !module.is_normal() => {
                  PathResolution::new(module.def().unwrap())
          if path.len() > 1 && !global_by_default && result.base_def() != Def::Err &&
             path[0].name != keywords::CrateRoot.name() && path[0].name != "$crate" {
              let unqualified_result = {
-                 match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
+                 match self.resolve_path(&[*path.last().unwrap()], Some(ns), false, span) {
                      PathResult::NonModule(path_res) => path_res.base_def(),
                      PathResult::Module(module) => module.def().unwrap(),
                      _ => return Some(result),
      fn resolve_path(&mut self,
                      path: &[Ident],
                      opt_ns: Option<Namespace>, // `None` indicates a module path
-                     record_used: Option<Span>)
+                     record_used: bool,
+                     path_span: Span)
                      -> PathResult<'a> {
          let mut module = None;
          let mut allow_super = true;
                  module = Some(self.graph_root);
                  continue
              } else if i == 0 && ns == TypeNS && ident.name == "$crate" {
-                 module = Some(self.resolve_crate_var(ident.ctxt));
+                 module = Some(self.resolve_crate_var(ident.ctxt, path_span));
                  continue
              }
  
              let binding = if let Some(module) = module {
-                 self.resolve_ident_in_module(module, ident, ns, false, record_used)
+                 self.resolve_ident_in_module(module, ident, ns, false, record_used, path_span)
              } else if opt_ns == Some(MacroNS) {
-                 self.resolve_lexical_macro_path_segment(ident, ns, record_used)
+                 self.resolve_lexical_macro_path_segment(ident, ns, record_used, path_span)
                      .map(MacroBinding::binding)
              } else {
-                 match self.resolve_ident_in_lexical_scope(ident, ns, record_used) {
+                 match self.resolve_ident_in_lexical_scope(ident, ns, record_used, path_span) {
                      Some(LexicalScopeBinding::Item(binding)) => Ok(binding),
                      Some(LexicalScopeBinding::Def(def))
                              if opt_ns == Some(TypeNS) || opt_ns == Some(ValueNS) => {
                              def, path.len() - 1
                          ));
                      }
-                     _ => Err(if record_used.is_some() { Determined } else { Undetermined }),
+                     _ => Err(if record_used { Determined } else { Undetermined }),
                  }
              };
  
                          ns: Namespace,
                          rib_index: usize,
                          mut def: Def,
-                         record_used: Option<Span>) -> Def {
+                         record_used: bool,
+                         span: Span) -> Def {
          let ribs = &self.ribs[ns][rib_index + 1..];
  
          // An invalid forward use of a type parameter from a previous default.
          if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind {
-             if let Some(span) = record_used {
+             if record_used {
                  resolve_error(self, span,
                          ResolutionError::ForwardDeclaredTyParam);
              }
  
          match def {
              Def::Upvar(..) => {
-                 span_bug!(record_used.unwrap_or(DUMMY_SP), "unexpected {:?} in bindings", def)
+                 span_bug!(span, "unexpected {:?} in bindings", def)
              }
              Def::Local(def_id) => {
                  for rib in ribs {
                              let depth = vec.len();
                              def = Def::Upvar(def_id, depth, function_id);
  
-                             if let Some(span) = record_used {
+                             if record_used {
                                  vec.push(Freevar {
                                      def: prev_def,
                                      span: span,
                              // This was an attempt to access an upvar inside a
                              // named function item. This is not allowed, so we
                              // report an error.
-                             if let Some(span) = record_used {
+                             if record_used {
                                  resolve_error(self, span,
                                          ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
                              }
                          }
                          ConstantItemRibKind => {
                              // Still doesn't deal with upvars
-                             if let Some(span) = record_used {
+                             if record_used {
                                  resolve_error(self, span,
                                          ResolutionError::AttemptToUseNonConstantValueInConstant);
                              }
                          ItemRibKind => {
                              // This was an attempt to use a type parameter outside
                              // its scope.
-                             if let Some(span) = record_used {
+                             if record_used {
                                  resolve_error(self, span,
                                                ResolutionError::TypeParametersFromOuterFunction);
                              }
                          }
                          ConstantItemRibKind => {
                              // see #9186
-                             if let Some(span) = record_used {
+                             if record_used {
                                  resolve_error(self, span,
                                                ResolutionError::OuterTypeParameterContext);
                              }
      fn lookup_typo_candidate<FilterFn>(&mut self,
                                         path: &[Ident],
                                         ns: Namespace,
-                                        filter_fn: FilterFn)
+                                        filter_fn: FilterFn,
+                                        span: Span)
                                         -> Option<Symbol>
          where FilterFn: Fn(Def) -> bool
      {
          } else {
              // Search in module.
              let mod_path = &path[..path.len() - 1];
-             if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS), None) {
+             if let PathResult::Module(module) = self.resolve_path(mod_path, Some(TypeNS),
+                                                                   false, span) {
                  add_module_candidates(module, &mut names);
              }
          }
                  continue
              }
              let ident = attr.path.segments[0].identifier;
-             let result = self.resolve_lexical_macro_path_segment(ident, MacroNS, None);
+             let result = self.resolve_lexical_macro_path_segment(ident,
+                                                                  MacroNS,
+                                                                  false,
+                                                                  attr.path.span);
              if let Ok(binding) = result {
                  if let SyntaxExtension::AttrProcMacro(..) = *binding.binding().get_macro(self) {
                      attr::mark_known(attr);
@@@ -3464,12 -3489,10 +3490,10 @@@ fn import_candidate_to_paths(suggestion
  /// When an entity with a given name is not available in scope, we search for
  /// entities with that name in all crates. This method allows outputting the
  /// results of this search in a programmer-friendly way
- fn show_candidates(session: &mut DiagnosticBuilder,
+ fn show_candidates(err: &mut DiagnosticBuilder,
+                    span: Span,
                     candidates: &[ImportSuggestion],
                     better: bool) {
-     // don't show more than MAX_CANDIDATES results, so
-     // we're consistent with the trait suggestions
-     const MAX_CANDIDATES: usize = 4;
  
      // we want consistent results across executions, but candidates are produced
      // by iterating through a hash map, so make sure they are ordered:
          1 => " is found in another module, you can import it",
          _ => "s are found in other modules, you can import them",
      };
+     let msg = format!("possible {}candidate{} into scope", better, msg_diff);
+     for candidate in &mut path_strings {
+         *candidate = format!("use {};\n", candidate);
+     }
  
-     let end = cmp::min(MAX_CANDIDATES, path_strings.len());
-     session.help(&format!("possible {}candidate{} into scope:{}{}",
-                           better,
-                           msg_diff,
-                           &path_strings[0..end].iter().map(|candidate| {
-                               format!("\n  `use {};`", candidate)
-                           }).collect::<String>(),
-                           if path_strings.len() > MAX_CANDIDATES {
-                               format!("\nand {} other candidates",
-                                       path_strings.len() - MAX_CANDIDATES)
-                           } else {
-                               "".to_owned()
-                           }
-                           ));
+     err.span_suggestions(span, &msg, path_strings);
  }
  
  /// A somewhat inefficient routine to obtain the name of a module.
index ff094d04c846289bdecf1b10cbfd5e24ba92b0d0,14b6650c49335bc0036fe2ef3b2667b0a73808ae..8e633ee59b67d7696323d460c5d553802927f23c
@@@ -15,6 -15,7 +15,6 @@@
  //! This API is completely unstable and subject to change.
  
  #![crate_name = "rustc_trans"]
 -#![unstable(feature = "rustc_private", issue = "27812")]
  #![crate_type = "dylib"]
  #![crate_type = "rlib"]
  #![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
  #![feature(libc)]
  #![feature(quote)]
  #![feature(rustc_diagnostic_macros)]
 -#![feature(rustc_private)]
  #![feature(slice_patterns)]
 -#![feature(staged_api)]
  #![feature(unicode)]
  #![feature(conservative_impl_trait)]
  
 +#![cfg_attr(stage0, unstable(feature = "rustc_private", issue = "27812"))]
 +#![cfg_attr(stage0, feature(rustc_private))]
 +#![cfg_attr(stage0, feature(staged_api))]
 +
  use rustc::dep_graph::WorkProduct;
  use syntax_pos::symbol::Symbol;
  
@@@ -86,9 -85,6 +86,6 @@@ pub mod back 
  
  pub mod diagnostics;
  
- #[macro_use]
- mod macros;
  mod abi;
  mod adt;
  mod asm;