diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 4e4fc8b3118ff..b30d5e384884e 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -18,8 +18,9 @@ use hir::def::Def; use hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE}; use ty::{self, TyCtxt}; use middle::privacy::AccessLevels; +use session::DiagnosticMessageId; use syntax::symbol::Symbol; -use syntax_pos::{Span, DUMMY_SP}; +use syntax_pos::{Span, MultiSpan, DUMMY_SP}; use syntax::ast; use syntax::ast::{NodeId, Attribute}; use syntax::feature_gate::{GateIssue, emit_feature_err, find_lang_feature_accepted_version}; @@ -597,8 +598,29 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { feature.as_str(), &r), None => format!("use of unstable library feature '{}'", &feature) }; - emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, - GateIssue::Library(Some(issue)), &msg); + + + let msp: MultiSpan = span.into(); + let cm = &self.sess.parse_sess.codemap(); + let span_key = msp.primary_span().and_then(|sp: Span| + if sp != DUMMY_SP { + let file = cm.lookup_char_pos(sp.lo()).file; + if file.name.starts_with("<") && file.name.ends_with(" macros>") { + None + } else { + Some(span) + } + } else { + None + } + ); + + let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone()); + let fresh = self.sess.one_time_diagnostics.borrow_mut().insert(error_id); + if fresh { + emit_feature_err(&self.sess.parse_sess, &feature.as_str(), span, + GateIssue::Library(Some(issue)), &msg); + } } Some(_) => { // Stable APIs are always ok to call and deprecated APIs are diff --git a/src/librustc/session/mod.rs b/src/librustc/session/mod.rs index 42c633dc83fe5..58e83faef90b6 100644 --- a/src/librustc/session/mod.rs +++ b/src/librustc/session/mod.rs @@ -75,10 +75,10 @@ pub struct Session { pub working_dir: (String, bool), pub lint_store: RefCell, pub buffered_lints: RefCell>, - /// Set of (LintId, Option, message) tuples tracking lint + /// Set of (DiagnosticId, Option, message) tuples tracking /// (sub)diagnostics that have been set once, but should not be set again, - /// in order to avoid redundantly verbose output (Issue #24690). - pub one_time_diagnostics: RefCell, String)>>, + /// in order to avoid redundantly verbose output (Issue #24690, #44953). + pub one_time_diagnostics: RefCell, String)>>, pub plugin_llvm_passes: RefCell>, pub plugin_attributes: RefCell>, pub crate_types: RefCell>, @@ -164,6 +164,13 @@ enum DiagnosticBuilderMethod { // add more variants as needed to support one-time diagnostics } +/// Diagnostic message id - used in order to avoid emitting the same message more than once +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum DiagnosticMessageId { + LintId(lint::LintId), + StabilityId(u32) +} + impl Session { pub fn local_crate_disambiguator(&self) -> CrateDisambiguator { match *self.crate_disambiguator.borrow() { @@ -360,7 +367,7 @@ impl Session { do_method() }, _ => { - let lint_id = lint::LintId::of(lint); + let lint_id = DiagnosticMessageId::LintId(lint::LintId::of(lint)); let id_span_message = (lint_id, span, message.to_owned()); let fresh = self.one_time_diagnostics.borrow_mut().insert(id_span_message); if fresh {