about summary refs log tree commit diff
path: root/src/librustc
diff options
context:
space:
mode:
authorMazdak Farrokhzad <twingoow@gmail.com>2019-07-07 17:00:17 +0200
committerGitHub <noreply@github.com>2019-07-07 17:00:17 +0200
commit3250b8ee596afc9881aee092279efaa57486d2ea (patch)
treec445db0b21aa62544140ff60894f770dc8fade07 /src/librustc
parent9cd75fb35f1d24f805c6759fd6236cd708b81ee1 (diff)
parent941653b528deb96d5ed13935143db14c45d99d6e (diff)
downloadrust-3250b8ee596afc9881aee092279efaa57486d2ea.tar.gz
rust-3250b8ee596afc9881aee092279efaa57486d2ea.zip
Rollup merge of #62042 - petrochenkov:macstab, r=matthewjasper
Support stability and deprecation checking for all macros

RELNOTES: Deprecation attributes on macros now have effect.

Fixes https://github.com/rust-lang/rust/issues/34079
Fixes https://github.com/rust-lang/rust/issues/49912
Unblocks https://github.com/rust-lang/rust/pull/62086
Unblocks https://github.com/rust-lang/rust/pull/61000
Diffstat (limited to 'src/librustc')
-rw-r--r--src/librustc/hir/lowering.rs5
-rw-r--r--src/librustc/hir/map/collector.rs1
-rw-r--r--src/librustc/hir/mod.rs2
-rw-r--r--src/librustc/lint/builtin.rs5
-rw-r--r--src/librustc/middle/lib_features.rs6
-rw-r--r--src/librustc/middle/stability.rs208
6 files changed, 135 insertions, 92 deletions
diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs
index 271fac544a4..2a9fd58f84b 100644
--- a/src/librustc/hir/lowering.rs
+++ b/src/librustc/hir/lowering.rs
@@ -90,6 +90,7 @@ pub struct LoweringContext<'a> {
     impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
     bodies: BTreeMap<hir::BodyId, hir::Body>,
     exported_macros: Vec<hir::MacroDef>,
+    non_exported_macro_attrs: Vec<ast::Attribute>,
 
     trait_impls: BTreeMap<DefId, Vec<hir::HirId>>,
 
@@ -252,6 +253,7 @@ pub fn lower_crate(
         trait_impls: BTreeMap::new(),
         modules: BTreeMap::new(),
         exported_macros: Vec::new(),
+        non_exported_macro_attrs: Vec::new(),
         catch_scopes: Vec::new(),
         loop_scopes: Vec::new(),
         is_in_loop_condition: false,
@@ -662,6 +664,7 @@ impl<'a> LoweringContext<'a> {
             attrs,
             span: c.span,
             exported_macros: hir::HirVec::from(self.exported_macros),
+            non_exported_macro_attrs: hir::HirVec::from(self.non_exported_macro_attrs),
             items: self.items,
             trait_items: self.trait_items,
             impl_items: self.impl_items,
@@ -4022,6 +4025,8 @@ impl<'a> LoweringContext<'a> {
                     body,
                     legacy: def.legacy,
                 });
+            } else {
+                self.non_exported_macro_attrs.extend(attrs.into_iter());
             }
             return None;
         }
diff --git a/src/librustc/hir/map/collector.rs b/src/librustc/hir/map/collector.rs
index 8a59f6b69bc..12ea772c1fb 100644
--- a/src/librustc/hir/map/collector.rs
+++ b/src/librustc/hir/map/collector.rs
@@ -119,6 +119,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> {
                 span,
                 // These fields are handled separately:
                 exported_macros: _,
+                non_exported_macro_attrs: _,
                 items: _,
                 trait_items: _,
                 impl_items: _,
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 7b760a87238..e7b37d40b4b 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -727,6 +727,8 @@ pub struct Crate {
     pub attrs: HirVec<Attribute>,
     pub span: Span,
     pub exported_macros: HirVec<MacroDef>,
+    // Attributes from non-exported macros, kept only for collecting the library feature list.
+    pub non_exported_macro_attrs: HirVec<Attribute>,
 
     // N.B., we use a BTreeMap here so that `visit_all_items` iterates
     // over the ids in increasing order. In principle it should not
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 45e598531b9..dd879ec6aff 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -5,10 +5,12 @@
 //! lints are all available in `rustc_lint::builtin`.
 
 use crate::lint::{LintPass, LateLintPass, LintArray};
+use crate::middle::stability;
 use crate::session::Session;
 use errors::{Applicability, DiagnosticBuilder};
 use syntax::ast;
 use syntax::source_map::Span;
+use syntax::symbol::Symbol;
 
 declare_lint! {
     pub EXCEEDING_BITSHIFTS,
@@ -461,6 +463,7 @@ pub enum BuiltinLintDiagnostics {
     UnusedImports(String, Vec<(Span, String)>),
     NestedImplTrait { outer_impl_trait_span: Span, inner_impl_trait_span: Span },
     RedundantImport(Vec<(Span, bool)>, ast::Ident),
+    DeprecatedMacro(Option<Symbol>, Span),
 }
 
 pub(crate) fn add_elided_lifetime_in_path_suggestion(
@@ -586,6 +589,8 @@ impl BuiltinLintDiagnostics {
                     );
                 }
             }
+            BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span) =>
+                stability::deprecation_suggestion(db, suggestion, span),
         }
     }
 }
diff --git a/src/librustc/middle/lib_features.rs b/src/librustc/middle/lib_features.rs
index 694b0a98629..0d6d016e507 100644
--- a/src/librustc/middle/lib_features.rs
+++ b/src/librustc/middle/lib_features.rs
@@ -144,6 +144,10 @@ impl Visitor<'tcx> for LibFeatureCollector<'tcx> {
 
 pub fn collect(tcx: TyCtxt<'_>) -> LibFeatures {
     let mut collector = LibFeatureCollector::new(tcx);
-    intravisit::walk_crate(&mut collector, tcx.hir().krate());
+    let krate = tcx.hir().krate();
+    for attr in &krate.non_exported_macro_attrs {
+        collector.visit_attribute(attr);
+    }
+    intravisit::walk_crate(&mut collector, krate);
     collector.lib_features
 }
diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs
index 7757336cf9c..5ab762ab225 100644
--- a/src/librustc/middle/stability.rs
+++ b/src/librustc/middle/stability.rs
@@ -4,6 +4,7 @@
 pub use self::StabilityLevel::*;
 
 use crate::lint::{self, Lint, in_derive_expansion};
+use crate::lint::builtin::BuiltinLintDiagnostics;
 use crate::hir::{self, Item, Generics, StructField, Variant, HirId};
 use crate::hir::def::{Res, DefKind};
 use crate::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId, LOCAL_CRATE};
@@ -11,12 +12,13 @@ use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use crate::ty::query::Providers;
 use crate::middle::privacy::AccessLevels;
 use crate::session::{DiagnosticMessageId, Session};
+use errors::DiagnosticBuilder;
 use syntax::symbol::{Symbol, sym};
 use syntax_pos::{Span, MultiSpan};
-use syntax::ast::Attribute;
+use syntax::ast::{Attribute, CRATE_NODE_ID};
 use syntax::errors::Applicability;
 use syntax::feature_gate::{GateIssue, emit_feature_err};
-use syntax::attr::{self, Stability, Deprecation};
+use syntax::attr::{self, Stability, Deprecation, RustcDeprecation};
 use crate::ty::{self, TyCtxt};
 use crate::util::nodemap::{FxHashSet, FxHashMap};
 
@@ -477,6 +479,36 @@ pub fn provide(providers: &mut Providers<'_>) {
     };
 }
 
+pub fn report_unstable(
+    sess: &Session, feature: Symbol, reason: Option<Symbol>, issue: u32, span: Span
+) {
+    let msg = match reason {
+        Some(r) => format!("use of unstable library feature '{}': {}", feature, r),
+        None => format!("use of unstable library feature '{}'", &feature)
+    };
+
+    let msp: MultiSpan = span.into();
+    let cm = &sess.parse_sess.source_map();
+    let span_key = msp.primary_span().and_then(|sp: Span|
+        if !sp.is_dummy() {
+            let file = cm.lookup_char_pos(sp.lo()).file;
+            if file.name.is_macros() {
+                None
+            } else {
+                Some(span)
+            }
+        } else {
+            None
+        }
+    );
+
+    let error_id = (DiagnosticMessageId::StabilityId(issue), span_key, msg.clone());
+    let fresh = sess.one_time_diagnostics.borrow_mut().insert(error_id);
+    if fresh {
+        emit_feature_err(&sess.parse_sess, feature, span, GateIssue::Library(Some(issue)), &msg);
+    }
+}
+
 /// Checks whether an item marked with `deprecated(since="X")` is currently
 /// deprecated (i.e., whether X is not greater than the current rustc version).
 pub fn deprecation_in_effect(since: &str) -> bool {
@@ -501,6 +533,79 @@ pub fn deprecation_in_effect(since: &str) -> bool {
     }
 }
 
+pub fn deprecation_suggestion(
+    diag: &mut DiagnosticBuilder<'_>, suggestion: Option<Symbol>, span: Span
+) {
+    if let Some(suggestion) = suggestion {
+        diag.span_suggestion(
+            span,
+            "replace the use of the deprecated item",
+            suggestion.to_string(),
+            Applicability::MachineApplicable,
+        );
+    }
+}
+
+fn deprecation_message_common(message: String, reason: Option<Symbol>) -> String {
+    match reason {
+        Some(reason) => format!("{}: {}", message, reason),
+        None => message,
+    }
+}
+
+pub fn deprecation_message(depr: &Deprecation, path: &str) -> (String, &'static Lint) {
+    let message = format!("use of deprecated item '{}'", path);
+    (deprecation_message_common(message, depr.note), lint::builtin::DEPRECATED)
+}
+
+pub fn rustc_deprecation_message(depr: &RustcDeprecation, path: &str) -> (String, &'static Lint) {
+    let (message, lint) = if deprecation_in_effect(&depr.since.as_str()) {
+        (format!("use of deprecated item '{}'", path), lint::builtin::DEPRECATED)
+    } else {
+        (format!("use of item '{}' that will be deprecated in future version {}", path, depr.since),
+         lint::builtin::DEPRECATED_IN_FUTURE)
+    };
+    (deprecation_message_common(message, Some(depr.reason)), lint)
+}
+
+pub fn early_report_deprecation(
+    sess: &Session,
+    message: &str,
+    suggestion: Option<Symbol>,
+    lint: &'static Lint,
+    span: Span,
+) {
+    if in_derive_expansion(span) {
+        return;
+    }
+
+    let diag = BuiltinLintDiagnostics::DeprecatedMacro(suggestion, span);
+    sess.buffer_lint_with_diagnostic(lint, CRATE_NODE_ID, span, message, diag);
+}
+
+fn late_report_deprecation(
+    tcx: TyCtxt<'_>,
+    message: &str,
+    suggestion: Option<Symbol>,
+    lint: &'static Lint,
+    span: Span,
+    def_id: DefId,
+    hir_id: HirId,
+) {
+    if in_derive_expansion(span) {
+        return;
+    }
+
+    let mut diag = tcx.struct_span_lint_hir(lint, hir_id, span, message);
+    if let hir::Node::Expr(_) = tcx.hir().get(hir_id) {
+        deprecation_suggestion(&mut diag, suggestion, span);
+    }
+    diag.emit();
+    if hir_id == hir::DUMMY_HIR_ID {
+        span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id);
+    }
+}
+
 struct Checker<'tcx> {
     tcx: TyCtxt<'tcx>,
 }
@@ -563,38 +668,6 @@ impl<'tcx> TyCtxt<'tcx> {
     /// deprecated. If the item is indeed deprecated, we will emit a deprecation lint attached to
     /// `id`.
     pub fn eval_stability(self, def_id: DefId, id: Option<HirId>, span: Span) -> EvalResult {
-        let lint_deprecated = |def_id: DefId,
-                               id: HirId,
-                               note: Option<Symbol>,
-                               suggestion: Option<Symbol>,
-                               message: &str,
-                               lint: &'static Lint| {
-            if in_derive_expansion(span) {
-                return;
-            }
-            let msg = if let Some(note) = note {
-                format!("{}: {}", message, note)
-            } else {
-                format!("{}", message)
-            };
-
-            let mut diag = self.struct_span_lint_hir(lint, id, span, &msg);
-            if let Some(suggestion) = suggestion {
-                if let hir::Node::Expr(_) = self.hir().get(id) {
-                    diag.span_suggestion(
-                        span,
-                        "replace the use of the deprecated item",
-                        suggestion.to_string(),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            diag.emit();
-            if id == hir::DUMMY_HIR_ID {
-                span_bug!(span, "emitted a {} lint with dummy HIR id: {:?}", lint.name, def_id);
-            }
-        };
-
         // Deprecated attributes apply in-crate and cross-crate.
         if let Some(id) = id {
             if let Some(depr_entry) = self.lookup_deprecation_entry(def_id) {
@@ -604,14 +677,9 @@ impl<'tcx> TyCtxt<'tcx> {
                                .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
 
                 if !skip {
-                    let path = self.def_path_str(def_id);
-                    let message = format!("use of deprecated item '{}'", path);
-                    lint_deprecated(def_id,
-                                    id,
-                                    depr_entry.attr.note,
-                                    None,
-                                    &message,
-                                    lint::builtin::DEPRECATED);
+                    let (message, lint) =
+                        deprecation_message(&depr_entry.attr, &self.def_path_str(def_id));
+                    late_report_deprecation(self, &message, None, lint, span, def_id, id);
                 }
             };
         }
@@ -631,27 +699,11 @@ impl<'tcx> TyCtxt<'tcx> {
         if let Some(id) = id {
             if let Some(stability) = stability {
                 if let Some(depr) = &stability.rustc_depr {
-                    let path = self.def_path_str(def_id);
-                    if deprecation_in_effect(&depr.since.as_str()) {
-                        let message = format!("use of deprecated item '{}'", path);
-                        lint_deprecated(def_id,
-                                        id,
-                                        Some(depr.reason),
-                                        depr.suggestion,
-                                        &message,
-                                        lint::builtin::DEPRECATED);
-                    } else {
-                        let message = format!("use of item '{}' \
-                                                that will be deprecated in future version {}",
-                                                path,
-                                                depr.since);
-                        lint_deprecated(def_id,
-                                        id,
-                                        Some(depr.reason),
-                                        depr.suggestion,
-                                        &message,
-                                        lint::builtin::DEPRECATED_IN_FUTURE);
-                    }
+                    let (message, lint) =
+                        rustc_deprecation_message(depr, &self.def_path_str(def_id));
+                    late_report_deprecation(
+                        self, &message, depr.suggestion, lint, span, def_id, id
+                    );
                 }
             }
         }
@@ -715,34 +767,8 @@ impl<'tcx> TyCtxt<'tcx> {
     pub fn check_stability(self, def_id: DefId, id: Option<HirId>, span: Span) {
         match self.eval_stability(def_id, id, span) {
             EvalResult::Allow => {}
-            EvalResult::Deny { feature, reason, issue } => {
-                let msg = match reason {
-                    Some(r) => format!("use of unstable library feature '{}': {}", feature, r),
-                    None => format!("use of unstable library feature '{}'", &feature)
-                };
-
-                let msp: MultiSpan = span.into();
-                let cm = &self.sess.parse_sess.source_map();
-                let span_key = msp.primary_span().and_then(|sp: Span|
-                    if !sp.is_dummy() {
-                        let file = cm.lookup_char_pos(sp.lo()).file;
-                        if file.name.is_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, span,
-                                     GateIssue::Library(Some(issue)), &msg);
-                }
-            }
+            EvalResult::Deny { feature, reason, issue } =>
+                report_unstable(self.sess, feature, reason, issue, span),
             EvalResult::Unmarked => {
                 // The API could be uncallable for other reasons, for example when a private module
                 // was referenced.