about summary refs log tree commit diff
path: root/src
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
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')
-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
-rw-r--r--src/librustc_plugin/registry.rs5
-rw-r--r--src/librustc_resolve/lib.rs15
-rw-r--r--src/librustc_resolve/macros.rs60
-rw-r--r--src/libserialize/json.rs14
-rw-r--r--src/libsyntax/attr/builtin.rs16
-rw-r--r--src/libsyntax/ext/base.rs21
-rw-r--r--src/libsyntax/ext/derive.rs6
-rw-r--r--src/libsyntax/ext/expand.rs86
-rw-r--r--src/libsyntax/ext/source_util.rs12
-rw-r--r--src/libsyntax/ext/tt/macro_rules.rs18
-rw-r--r--src/libsyntax/feature_gate.rs22
-rw-r--r--src/libsyntax/parse/lexer/mod.rs2
-rw-r--r--src/libsyntax_ext/asm.rs9
-rw-r--r--src/libsyntax_ext/concat_idents.rs11
-rw-r--r--src/libsyntax_ext/deriving/decodable.rs2
-rw-r--r--src/libsyntax_ext/deriving/encodable.rs2
-rw-r--r--src/libsyntax_ext/deriving/mod.rs66
-rw-r--r--src/libsyntax_ext/format.rs47
-rw-r--r--src/libsyntax_ext/global_asm.rs12
-rw-r--r--src/libsyntax_ext/lib.rs84
-rw-r--r--src/libsyntax_ext/log_syntax.rs12
-rw-r--r--src/libsyntax_ext/proc_macro_server.rs4
-rw-r--r--src/libsyntax_ext/test_case.rs9
-rw-r--r--src/libsyntax_ext/trace_macros.rs11
-rw-r--r--src/libsyntax_pos/symbol.rs20
-rw-r--r--src/test/run-pass/macros/macro-stability.rs2
-rw-r--r--src/test/ui-fulldeps/deprecated-derive.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-asm2.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-concat_idents.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-concat_idents2.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-concat_idents3.stderr4
-rw-r--r--src/test/ui/feature-gates/feature-gate-custom_test_frameworks.rs3
-rw-r--r--src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr11
-rw-r--r--src/test/ui/feature-gates/feature-gate-format_args_nl.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-global_asm.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-log_syntax.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-log_syntax2.stderr2
-rw-r--r--src/test/ui/feature-gates/feature-gate-trace_macros.stderr2
-rw-r--r--src/test/ui/macros/auxiliary/deprecated-macros.rs3
-rw-r--r--src/test/ui/macros/auxiliary/unstable-macros.rs10
-rw-r--r--src/test/ui/macros/macro-deprecation.rs13
-rw-r--r--src/test/ui/macros/macro-deprecation.stderr14
-rw-r--r--src/test/ui/macros/macro-stability.rs20
-rw-r--r--src/test/ui/macros/macro-stability.stderr36
-rw-r--r--src/test/ui/rust-unstable-column-gated.rs2
-rw-r--r--src/test/ui/rust-unstable-column-gated.stderr5
-rw-r--r--src/test/ui/trace_macros-gate.stderr8
54 files changed, 517 insertions, 431 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.
diff --git a/src/librustc_plugin/registry.rs b/src/librustc_plugin/registry.rs
index ec2855f826a..bb3c950edae 100644
--- a/src/librustc_plugin/registry.rs
+++ b/src/librustc_plugin/registry.rs
@@ -84,10 +84,7 @@ impl<'a> Registry<'a> {
     /// Register a syntax extension of any kind.
     ///
     /// This is the most general hook into `libsyntax`'s expansion behavior.
-    pub fn register_syntax_extension(&mut self, name: ast::Name, mut extension: SyntaxExtension) {
-        if extension.def_info.is_none() {
-            extension.def_info = Some((ast::CRATE_NODE_ID, self.krate_span));
-        }
+    pub fn register_syntax_extension(&mut self, name: ast::Name, extension: SyntaxExtension) {
         self.syntax_exts.push((name, extension));
     }
 
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index 13b9855dbd7..66410482cc6 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1666,10 +1666,7 @@ pub struct Resolver<'a> {
     non_macro_attrs: [Lrc<SyntaxExtension>; 2],
     macro_defs: FxHashMap<Mark, DefId>,
     local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
-
-    /// List of crate local macros that we need to warn about as being unused.
-    /// Right now this only includes macro_rules! macros, and macros 2.0.
-    unused_macros: FxHashSet<DefId>,
+    unused_macros: NodeMap<Span>,
 
     /// Maps the `Mark` of an expansion to its containing module or block.
     invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
@@ -1687,6 +1684,9 @@ pub struct Resolver<'a> {
     current_type_ascription: Vec<Span>,
 
     injected_crate: Option<Module<'a>>,
+
+    /// Features enabled for this crate.
+    active_features: FxHashSet<Symbol>,
 }
 
 /// Nothing really interesting here; it just provides memory for the rest of the crate.
@@ -1925,6 +1925,7 @@ impl<'a> Resolver<'a> {
         let mut macro_defs = FxHashMap::default();
         macro_defs.insert(Mark::root(), root_def_id);
 
+        let features = session.features_untracked();
         let non_macro_attr = |mark_used| Lrc::new(SyntaxExtension::default(
             SyntaxExtensionKind::NonMacroAttr { mark_used }, session.edition()
         ));
@@ -2009,9 +2010,13 @@ impl<'a> Resolver<'a> {
             name_already_seen: FxHashMap::default(),
             potentially_unused_imports: Vec::new(),
             struct_constructors: Default::default(),
-            unused_macros: FxHashSet::default(),
+            unused_macros: Default::default(),
             current_type_ascription: Vec::new(),
             injected_crate: None,
+            active_features:
+                features.declared_lib_features.iter().map(|(feat, ..)| *feat)
+                    .chain(features.declared_lang_features.iter().map(|(feat, ..)| *feat))
+                    .collect(),
         }
     }
 
diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs
index 0955c425f2f..f26c3b8ae6a 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -9,10 +9,10 @@ use crate::resolve_imports::ImportResolver;
 use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
 use rustc::hir::def::{self, DefKind, NonMacroAttrKind};
 use rustc::hir::map::{self, DefCollector};
-use rustc::{ty, lint};
-use rustc::{bug, span_bug};
+use rustc::middle::stability;
+use rustc::{ty, lint, span_bug};
 use syntax::ast::{self, Ident};
-use syntax::attr;
+use syntax::attr::{self, StabilityLevel};
 use syntax::errors::DiagnosticBuilder;
 use syntax::ext::base::{self, Determinacy};
 use syntax::ext::base::{MacroKind, SyntaxExtension};
@@ -230,16 +230,19 @@ impl<'a> base::Resolver for Resolver<'a> {
             Err(determinacy) => return Err(determinacy),
         };
 
+        let span = invoc.span();
+        let path = fast_print_path(path);
         let format = match kind {
-            MacroKind::Derive => format!("derive({})", fast_print_path(path)),
-            _ => fast_print_path(path),
+            MacroKind::Derive => format!("derive({})", path),
+            _ => path.clone(),
         };
-        invoc.expansion_data.mark.set_expn_info(ext.expn_info(invoc.span(), &format));
+        invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, &format));
+
+        self.check_stability_and_deprecation(&ext, &path, span);
 
         if let Res::Def(_, def_id) = res {
             if after_derive {
-                self.session.span_err(invoc.span(),
-                                      "macro attributes must be placed before `#[derive]`");
+                self.session.span_err(span, "macro attributes must be placed before `#[derive]`");
             }
             self.macro_defs.insert(invoc.expansion_data.mark, def_id);
             let normal_module_def_id =
@@ -259,14 +262,10 @@ impl<'a> base::Resolver for Resolver<'a> {
     }
 
     fn check_unused_macros(&self) {
-        for did in self.unused_macros.iter() {
-            if let Some((id, span)) = self.macro_map[did].def_info {
-                let lint = lint::builtin::UNUSED_MACROS;
-                let msg = "unused macro definition";
-                self.session.buffer_lint(lint, id, span, msg);
-            } else {
-                bug!("attempted to create unused macro error, but span not available");
-            }
+        for (&node_id, &span) in self.unused_macros.iter() {
+            self.session.buffer_lint(
+                lint::builtin::UNUSED_MACROS, node_id, span, "unused macro definition"
+            );
         }
     }
 }
@@ -323,7 +322,9 @@ impl<'a> Resolver<'a> {
 
         match res {
             Res::Def(DefKind::Macro(macro_kind), def_id) => {
-                self.unused_macros.remove(&def_id);
+                if let Some(node_id) = self.definitions.as_local_node_id(def_id) {
+                    self.unused_macros.remove(&node_id);
+                }
                 if macro_kind == MacroKind::ProcMacroStub {
                     let msg = "can't use a procedural macro from the same crate that defines it";
                     self.session.span_err(path.span, msg);
@@ -1009,6 +1010,27 @@ impl<'a> Resolver<'a> {
         }
     }
 
+    fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &str, span: Span) {
+        if let Some(stability) = &ext.stability {
+            if let StabilityLevel::Unstable { reason, issue } = stability.level {
+                let feature = stability.feature;
+                if !self.active_features.contains(&feature) && !span.allows_unstable(feature) {
+                    stability::report_unstable(self.session, feature, reason, issue, span);
+                }
+            }
+            if let Some(depr) = &stability.rustc_depr {
+                let (message, lint) = stability::rustc_deprecation_message(depr, path);
+                stability::early_report_deprecation(
+                    self.session, &message, depr.suggestion, lint, span
+                );
+            }
+        }
+        if let Some(depr) = &ext.deprecation {
+            let (message, lint) = stability::deprecation_message(depr, path);
+            stability::early_report_deprecation(self.session, &message, None, lint, span);
+        }
+    }
+
     fn prohibit_imported_non_macro_attrs(&self, binding: Option<&'a NameBinding<'a>>,
                                          res: Option<Res>, span: Span) {
         if let Some(Res::NonMacroAttr(kind)) = res {
@@ -1157,13 +1179,13 @@ impl<'a> Resolver<'a> {
                             (res, vis, item.span, expansion, IsMacroExport));
             } else {
                 self.check_reserved_macro_name(ident, res);
-                self.unused_macros.insert(def_id);
+                self.unused_macros.insert(item.id, item.span);
             }
         } else {
             let module = self.current_module;
             let vis = self.resolve_visibility(&item.vis);
             if vis != ty::Visibility::Public {
-                self.unused_macros.insert(def_id);
+                self.unused_macros.insert(item.id, item.span);
             }
             self.define(module, ident, MacroNS, (res, vis, item.span, expansion));
         }
diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs
index 726306d60ce..d0007074a82 100644
--- a/src/libserialize/json.rs
+++ b/src/libserialize/json.rs
@@ -103,8 +103,8 @@
 //!
 //! ```rust
 //! # #![feature(rustc_private)]
-//! extern crate serialize;
-//! use serialize::json::{self, ToJson, Json};
+//! extern crate serialize as rustc_serialize;
+//! use rustc_serialize::json::{self, ToJson, Json};
 //!
 //! // A custom data structure
 //! struct ComplexNum {
@@ -120,7 +120,7 @@
 //! }
 //!
 //! // Only generate `RustcEncodable` trait implementation
-//! #[derive(Encodable)]
+//! #[derive(RustcEncodable)]
 //! pub struct ComplexNumRecord {
 //!     uid: u8,
 //!     dsc: String,
@@ -143,12 +143,12 @@
 //!
 //! ```rust
 //! # #![feature(rustc_private)]
-//! extern crate serialize;
+//! extern crate serialize as rustc_serialize;
 //! use std::collections::BTreeMap;
-//! use serialize::json::{self, Json, ToJson};
+//! use rustc_serialize::json::{self, Json, ToJson};
 //!
-//! // Only generate `Decodable` trait implementation
-//! #[derive(Decodable)]
+//! // Only generate `RustcDecodable` trait implementation
+//! #[derive(RustcDecodable)]
 //! pub struct TestStruct {
 //!     data_int: u8,
 //!     data_str: String,
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 752ab5d474d..b41f1047fcb 100644
--- a/src/libsyntax/attr/builtin.rs
+++ b/src/libsyntax/attr/builtin.rs
@@ -135,6 +135,19 @@ pub enum StabilityLevel {
     Stable { since: Symbol },
 }
 
+impl Stability {
+    pub fn unstable(feature: Symbol, reason: Option<Symbol>, issue: u32) -> Stability {
+        Stability {
+            level: StabilityLevel::Unstable { reason, issue },
+            feature,
+            rustc_depr: None,
+            const_stability: None,
+            promotable: false,
+            allow_const_fn_ptr: false,
+        }
+    }
+}
+
 impl StabilityLevel {
     pub fn is_unstable(&self) -> bool {
         if let StabilityLevel::Unstable {..} = *self {
@@ -171,7 +184,8 @@ pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool
     })
 }
 
-/// Finds the first stability attribute. `None` if none exists.
+/// Collects stability info from all stability attributes in `attrs`.
+/// Returns `None` if no stability attributes are found.
 pub fn find_stability(sess: &ParseSess, attrs: &[Attribute],
                       item_sp: Span) -> Option<Stability> {
     find_stability_generic(sess, attrs.iter(), item_sp)
diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs
index 318a5a3a82a..15c0b6ca5aa 100644
--- a/src/libsyntax/ext/base.rs
+++ b/src/libsyntax/ext/base.rs
@@ -1,5 +1,5 @@
 use crate::ast::{self, Attribute, Name, PatKind};
-use crate::attr::HasAttrs;
+use crate::attr::{HasAttrs, Stability, Deprecation};
 use crate::source_map::{SourceMap, Spanned, respan};
 use crate::edition::Edition;
 use crate::ext::expand::{self, AstFragment, Invocation};
@@ -606,8 +606,8 @@ pub enum SyntaxExtensionKind {
 pub struct SyntaxExtension {
     /// A syntax extension kind.
     pub kind: SyntaxExtensionKind,
-    /// Some info about the macro's definition point.
-    pub def_info: Option<(ast::NodeId, Span)>,
+    /// Span of the macro definition.
+    pub span: Span,
     /// Hygienic properties of spans produced by this macro by default.
     pub default_transparency: Transparency,
     /// Whitelist of unstable features that are treated as stable inside this macro.
@@ -616,8 +616,10 @@ pub struct SyntaxExtension {
     pub allow_internal_unsafe: bool,
     /// Enables the macro helper hack (`ident!(...)` -> `$crate::ident!(...)`) for this macro.
     pub local_inner_macros: bool,
-    /// The macro's feature name and tracking issue number if it is unstable.
-    pub unstable_feature: Option<(Symbol, u32)>,
+    /// The macro's stability info.
+    pub stability: Option<Stability>,
+    /// The macro's deprecation info.
+    pub deprecation: Option<Deprecation>,
     /// Names of helper attributes registered by this macro.
     pub helper_attrs: Vec<Symbol>,
     /// Edition of the crate in which this macro is defined.
@@ -657,12 +659,13 @@ impl SyntaxExtension {
     /// Constructs a syntax extension with default properties.
     pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension {
         SyntaxExtension {
-            def_info: None,
+            span: DUMMY_SP,
             default_transparency: kind.default_transparency(),
             allow_internal_unstable: None,
             allow_internal_unsafe: false,
             local_inner_macros: false,
-            unstable_feature: None,
+            stability: None,
+            deprecation: None,
             helper_attrs: Vec::new(),
             edition,
             kind,
@@ -681,7 +684,7 @@ impl SyntaxExtension {
         ExpnInfo {
             call_site,
             format: self.expn_format(Symbol::intern(format)),
-            def_site: self.def_info.map(|(_, span)| span),
+            def_site: Some(self.span),
             default_transparency: self.default_transparency,
             allow_internal_unstable: self.allow_internal_unstable.clone(),
             allow_internal_unsafe: self.allow_internal_unsafe,
@@ -738,7 +741,6 @@ pub struct ExpansionData {
     pub depth: usize,
     pub module: Rc<ModuleData>,
     pub directory_ownership: DirectoryOwnership,
-    pub crate_span: Option<Span>,
 }
 
 /// One of these is made during expansion and incrementally updated as we go;
@@ -768,7 +770,6 @@ impl<'a> ExtCtxt<'a> {
                 depth: 0,
                 module: Rc::new(ModuleData { mod_path: Vec::new(), directory: PathBuf::new() }),
                 directory_ownership: DirectoryOwnership::Owned { relative: None },
-                crate_span: None,
             },
             expansions: FxHashMap::default(),
         }
diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs
index 3b4243ed24f..2a56f3dd756 100644
--- a/src/libsyntax/ext/derive.rs
+++ b/src/libsyntax/ext/derive.rs
@@ -63,11 +63,11 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P
 
     let span = span.with_ctxt(cx.backtrace());
     item.visit_attrs(|attrs| {
-        if names.contains(&Symbol::intern("Eq")) && names.contains(&Symbol::intern("PartialEq")) {
-            let meta = cx.meta_word(span, Symbol::intern("structural_match"));
+        if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) {
+            let meta = cx.meta_word(span, sym::structural_match);
             attrs.push(cx.attribute(span, meta));
         }
-        if names.contains(&Symbol::intern("Copy")) {
+        if names.contains(&sym::Copy) {
             let meta = cx.meta_word(span, sym::rustc_copy_clone_marker);
             attrs.push(cx.attribute(span, meta));
         }
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6fbd2ab7c43..74ef5cbe917 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -243,7 +243,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         module.directory.pop();
         self.cx.root_path = module.directory.clone();
         self.cx.current_expansion.module = Rc::new(module);
-        self.cx.current_expansion.crate_span = Some(krate.span);
 
         let orig_mod_span = krate.module.inner;
 
@@ -488,7 +487,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
 
     fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option<AstFragment> {
         if invoc.fragment_kind == AstFragmentKind::ForeignItems &&
-           !self.cx.ecfg.macros_in_extern_enabled() {
+           !self.cx.ecfg.macros_in_extern() {
             if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else {
                 emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern,
                                  invoc.span(), GateIssue::Language,
@@ -668,40 +667,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
         };
         let path = &mac.node.path;
 
-        let validate = |this: &mut Self| {
-            // feature-gate the macro invocation
-            if let Some((feature, issue)) = ext.unstable_feature {
-                let crate_span = this.cx.current_expansion.crate_span.unwrap();
-                // don't stability-check macros in the same crate
-                // (the only time this is null is for syntax extensions registered as macros)
-                if ext.def_info.map_or(false, |(_, def_span)| !crate_span.contains(def_span))
-                    && !span.allows_unstable(feature)
-                    && this.cx.ecfg.features.map_or(true, |feats| {
-                    // macro features will count as lib features
-                    !feats.declared_lib_features.iter().any(|&(feat, _)| feat == feature)
-                }) {
-                    let explain = format!("macro {}! is unstable", path);
-                    emit_feature_err(this.cx.parse_sess, feature, span,
-                                     GateIssue::Library(Some(issue)), &explain);
-                    this.cx.trace_macros_diag();
-                }
-            }
-
-            Ok(())
-        };
-
         let opt_expanded = match &ext.kind {
+            SyntaxExtensionKind::Bang(expander) => {
+                self.gate_proc_macro_expansion_kind(span, kind);
+                let tok_result = expander.expand(self.cx, span, mac.node.stream());
+                let result = self.parse_ast_fragment(tok_result, kind, path, span);
+                self.gate_proc_macro_expansion(span, &result);
+                result
+            }
             SyntaxExtensionKind::LegacyBang(expander) => {
-                if let Err(dummy_span) = validate(self) {
-                    dummy_span
-                } else {
-                    kind.make_from(expander.expand(
-                        self.cx,
-                        span,
-                        mac.node.stream(),
-                        ext.def_info.map(|(_, s)| s),
-                    ))
-                }
+                let tok_result = expander.expand(self.cx, span, mac.node.stream(), Some(ext.span));
+                kind.make_from(tok_result)
             }
 
             SyntaxExtensionKind::Attr(..) |
@@ -718,14 +694,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
                 self.cx.trace_macros_diag();
                 kind.dummy(span)
             }
-
-            SyntaxExtensionKind::Bang(expander) => {
-                self.gate_proc_macro_expansion_kind(span, kind);
-                let tok_result = expander.expand(self.cx, span, mac.node.stream());
-                let result = self.parse_ast_fragment(tok_result, kind, path, span);
-                self.gate_proc_macro_expansion(span, &result);
-                result
-            }
         };
 
         if opt_expanded.is_some() {
@@ -951,7 +919,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
                         })
                         .map(|i| attrs.remove(i));
         if let Some(attr) = &attr {
-            if !self.cx.ecfg.enable_custom_inner_attributes() &&
+            if !self.cx.ecfg.custom_inner_attributes() &&
                attr.style == ast::AttrStyle::Inner && attr.path != sym::test {
                 emit_feature_err(&self.cx.parse_sess, sym::custom_inner_attributes,
                                  attr.span, GateIssue::Language,
@@ -1464,19 +1432,6 @@ pub struct ExpansionConfig<'feat> {
     pub keep_macs: bool,
 }
 
-macro_rules! feature_tests {
-    ($( fn $getter:ident = $field:ident, )*) => {
-        $(
-            pub fn $getter(&self) -> bool {
-                match self.features {
-                    Some(&Features { $field: true, .. }) => true,
-                    _ => false,
-                }
-            }
-        )*
-    }
-}
-
 impl<'feat> ExpansionConfig<'feat> {
     pub fn default(crate_name: String) -> ExpansionConfig<'static> {
         ExpansionConfig {
@@ -1490,20 +1445,13 @@ impl<'feat> ExpansionConfig<'feat> {
         }
     }
 
-    feature_tests! {
-        fn enable_asm = asm,
-        fn enable_custom_test_frameworks = custom_test_frameworks,
-        fn enable_global_asm = global_asm,
-        fn enable_log_syntax = log_syntax,
-        fn enable_concat_idents = concat_idents,
-        fn enable_trace_macros = trace_macros,
-        fn enable_allow_internal_unstable = allow_internal_unstable,
-        fn enable_format_args_nl = format_args_nl,
-        fn macros_in_extern_enabled = macros_in_extern,
-        fn proc_macro_hygiene = proc_macro_hygiene,
+    fn macros_in_extern(&self) -> bool {
+        self.features.map_or(false, |features| features.macros_in_extern)
     }
-
-    fn enable_custom_inner_attributes(&self) -> bool {
+    fn proc_macro_hygiene(&self) -> bool {
+        self.features.map_or(false, |features| features.proc_macro_hygiene)
+    }
+    fn custom_inner_attributes(&self) -> bool {
         self.features.map_or(false, |features| features.custom_inner_attributes)
     }
 }
diff --git a/src/libsyntax/ext/source_util.rs b/src/libsyntax/ext/source_util.rs
index 4e2aab46542..c2ba8b983f5 100644
--- a/src/libsyntax/ext/source_util.rs
+++ b/src/libsyntax/ext/source_util.rs
@@ -4,7 +4,7 @@ use crate::ext::build::AstBuilder;
 use crate::parse::{self, token, DirectoryOwnership};
 use crate::print::pprust;
 use crate::ptr::P;
-use crate::symbol::{Symbol, sym};
+use crate::symbol::Symbol;
 use crate::tokenstream;
 
 use smallvec::SmallVec;
@@ -41,16 +41,6 @@ pub fn expand_column(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTr
     base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1))
 }
 
-/* __rust_unstable_column!(): expands to the current column number */
-pub fn expand_column_gated(cx: &mut ExtCtxt<'_>, sp: Span, tts: &[tokenstream::TokenTree])
-                  -> Box<dyn base::MacResult+'static> {
-    if sp.allows_unstable(sym::__rust_unstable_column) {
-        expand_column(cx, sp, tts)
-    } else {
-        cx.span_fatal(sp, "the __rust_unstable_column macro is unstable");
-    }
-}
-
 /// file!(): expands to the current filename */
 /// The source_file (`loc.file`) contains a bunch more information we could spit
 /// out if we wanted.
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs
index cf3c748cd82..665c794422d 100644
--- a/src/libsyntax/ext/tt/macro_rules.rs
+++ b/src/libsyntax/ext/tt/macro_rules.rs
@@ -422,8 +422,6 @@ pub fn compile(
                 })
         });
 
-    let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe);
-
     let mut local_inner_macros = false;
     if let Some(macro_export) = attr::find_by_name(&def.attrs, sym::macro_export) {
         if let Some(l) = macro_export.meta_item_list() {
@@ -431,23 +429,15 @@ pub fn compile(
         }
     }
 
-    let unstable_feature =
-        attr::find_stability(&sess, &def.attrs, def.span).and_then(|stability| {
-            if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
-                Some((stability.feature, issue))
-            } else {
-                None
-            }
-        });
-
     SyntaxExtension {
         kind: SyntaxExtensionKind::LegacyBang(expander),
-        def_info: Some((def.id, def.span)),
+        span: def.span,
         default_transparency,
         allow_internal_unstable,
-        allow_internal_unsafe,
+        allow_internal_unsafe: attr::contains_name(&def.attrs, sym::allow_internal_unsafe),
         local_inner_macros,
-        unstable_feature,
+        stability: attr::find_stability(&sess, &def.attrs, def.span),
+        deprecation: attr::find_deprecation(&sess, &def.attrs, def.span),
         helper_attrs: Vec::new(),
         edition,
     }
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index 2b242a71ad4..f4f0d041e64 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -1568,7 +1568,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     (sym::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated),
     (sym::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable,
                     sym::custom_test_frameworks,
-                    EXPLAIN_CUSTOM_TEST_FRAMEWORKS,
+                    "custom test frameworks are an unstable feature",
                     cfg_fn!(custom_test_frameworks))),
 ];
 
@@ -1819,26 +1819,6 @@ const EXPLAIN_BOX_SYNTAX: &str =
 pub const EXPLAIN_STMT_ATTR_SYNTAX: &str =
     "attributes on expressions are experimental";
 
-pub const EXPLAIN_ASM: &str =
-    "inline assembly is not stable enough for use and is subject to change";
-
-pub const EXPLAIN_GLOBAL_ASM: &str =
-    "`global_asm!` is not stable enough for use and is subject to change";
-
-pub const EXPLAIN_CUSTOM_TEST_FRAMEWORKS: &str =
-    "custom test frameworks are an unstable feature";
-
-pub const EXPLAIN_LOG_SYNTAX: &str =
-    "`log_syntax!` is not stable enough for use and is subject to change";
-
-pub const EXPLAIN_CONCAT_IDENTS: &str =
-    "`concat_idents` is not stable enough for use and is subject to change";
-
-pub const EXPLAIN_FORMAT_ARGS_NL: &str =
-    "`format_args_nl` is only for internal language use and is subject to change";
-
-pub const EXPLAIN_TRACE_MACROS: &str =
-    "`trace_macros` is not stable enough for use and is subject to change";
 pub const EXPLAIN_ALLOW_INTERNAL_UNSTABLE: &str =
     "allow_internal_unstable side-steps feature gating and stability checks";
 pub const EXPLAIN_ALLOW_INTERNAL_UNSAFE: &str =
diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs
index 1abbf0ff1ee..d0c4e8d6a56 100644
--- a/src/libsyntax/parse/lexer/mod.rs
+++ b/src/libsyntax/parse/lexer/mod.rs
@@ -613,7 +613,7 @@ impl<'a> StringReader<'a> {
         if num_digits == 0 {
             self.err_span_(start_bpos, self.pos, "no valid digits found for number");
 
-            return (token::Integer, Symbol::intern("0"));
+            return (token::Integer, sym::integer(0));
         }
 
         // might be a float, but don't be greedy if this is actually an
diff --git a/src/libsyntax_ext/asm.rs b/src/libsyntax_ext/asm.rs
index b015815ac9c..c1c2732605c 100644
--- a/src/libsyntax_ext/asm.rs
+++ b/src/libsyntax_ext/asm.rs
@@ -8,7 +8,6 @@ use errors::DiagnosticBuilder;
 
 use syntax::ast;
 use syntax::ext::base::{self, *};
-use syntax::feature_gate;
 use syntax::parse;
 use syntax::parse::token::{self, Token};
 use syntax::ptr::P;
@@ -46,14 +45,6 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt<'_>,
                        sp: Span,
                        tts: &[tokenstream::TokenTree])
                        -> Box<dyn base::MacResult + 'cx> {
-    if !cx.ecfg.enable_asm() {
-        feature_gate::emit_feature_err(&cx.parse_sess,
-                                       sym::asm,
-                                       sp,
-                                       feature_gate::GateIssue::Language,
-                                       feature_gate::EXPLAIN_ASM);
-    }
-
     let mut inline_asm = match parse_inline_asm(cx, sp, tts) {
         Ok(Some(inline_asm)) => inline_asm,
         Ok(None) => return DummyResult::expr(sp),
diff --git a/src/libsyntax_ext/concat_idents.rs b/src/libsyntax_ext/concat_idents.rs
index 8f061abc77b..df919141603 100644
--- a/src/libsyntax_ext/concat_idents.rs
+++ b/src/libsyntax_ext/concat_idents.rs
@@ -2,25 +2,16 @@ use rustc_data_structures::thin_vec::ThinVec;
 
 use syntax::ast;
 use syntax::ext::base::{self, *};
-use syntax::feature_gate;
 use syntax::parse::token::{self, Token};
 use syntax::ptr::P;
 use syntax_pos::Span;
-use syntax_pos::symbol::{Symbol, sym};
+use syntax_pos::symbol::Symbol;
 use syntax::tokenstream::TokenTree;
 
 pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt<'_>,
                               sp: Span,
                               tts: &[TokenTree])
                               -> Box<dyn base::MacResult + 'cx> {
-    if !cx.ecfg.enable_concat_idents() {
-        feature_gate::emit_feature_err(&cx.parse_sess,
-                                       sym::concat_idents,
-                                       sp,
-                                       feature_gate::GateIssue::Language,
-                                       feature_gate::EXPLAIN_CONCAT_IDENTS);
-    }
-
     if tts.is_empty() {
         cx.span_err(sp, "concat_idents! takes 1 or more arguments.");
         return DummyResult::any(sp);
diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs
index d773f3ff7bc..8009f42b8cf 100644
--- a/src/libsyntax_ext/deriving/decodable.rs
+++ b/src/libsyntax_ext/deriving/decodable.rs
@@ -3,7 +3,6 @@
 use crate::deriving::{self, pathvec_std};
 use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
-use crate::deriving::warn_if_deprecated;
 
 use syntax::ast;
 use syntax::ast::{Expr, MetaItem, Mutability};
@@ -26,7 +25,6 @@ pub fn expand_deriving_decodable(cx: &mut ExtCtxt<'_>,
                                  mitem: &MetaItem,
                                  item: &Annotatable,
                                  push: &mut dyn FnMut(Annotatable)) {
-    warn_if_deprecated(cx, span, "Decodable");
     expand_deriving_decodable_imp(cx, span, mitem, item, push, "serialize")
 }
 
diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs
index faaedba3e77..cd89a42cf82 100644
--- a/src/libsyntax_ext/deriving/encodable.rs
+++ b/src/libsyntax_ext/deriving/encodable.rs
@@ -85,7 +85,6 @@
 use crate::deriving::{self, pathvec_std};
 use crate::deriving::generic::*;
 use crate::deriving::generic::ty::*;
-use crate::deriving::warn_if_deprecated;
 
 use syntax::ast::{Expr, ExprKind, MetaItem, Mutability};
 use syntax::ext::base::{Annotatable, ExtCtxt};
@@ -107,7 +106,6 @@ pub fn expand_deriving_encodable(cx: &mut ExtCtxt<'_>,
                                  mitem: &MetaItem,
                                  item: &Annotatable,
                                  push: &mut dyn FnMut(Annotatable)) {
-    warn_if_deprecated(cx, span, "Encodable");
     expand_deriving_encodable_imp(cx, span, mitem, item, push, "serialize")
 }
 
diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs
index aa9913d436c..e491e93256d 100644
--- a/src/libsyntax_ext/deriving/mod.rs
+++ b/src/libsyntax_ext/deriving/mod.rs
@@ -2,6 +2,7 @@
 
 use rustc_data_structures::sync::Lrc;
 use syntax::ast::{self, MetaItem};
+use syntax::attr::Deprecation;
 use syntax::edition::Edition;
 use syntax::ext::base::{Annotatable, ExtCtxt, Resolver, MultiItemModifier};
 use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind};
@@ -60,10 +61,10 @@ impl MultiItemModifier for BuiltinDerive {
 }
 
 macro_rules! derive_traits {
-    ($( $name:expr => $func:path, )+) => {
+    ($( [$deprecation:expr] $name:ident => $func:path, )+) => {
         pub fn is_builtin_trait(name: ast::Name) -> bool {
-            match &*name.as_str() {
-                $( $name )|+ => true,
+            match name {
+                $( sym::$name )|+ => true,
                 _ => false,
             }
         }
@@ -79,8 +80,12 @@ macro_rules! derive_traits {
 
             $(
                 resolver.add_builtin(
-                    ast::Ident::with_empty_ctxt(Symbol::intern($name)),
+                    ast::Ident::with_empty_ctxt(sym::$name),
                     Lrc::new(SyntaxExtension {
+                        deprecation: $deprecation.map(|msg| Deprecation {
+                            since: Some(Symbol::intern("1.0.0")),
+                            note: Some(Symbol::intern(msg)),
+                        }),
                         allow_internal_unstable: allow_internal_unstable.clone(),
                         ..SyntaxExtension::default(
                             SyntaxExtensionKind::LegacyDerive(Box::new(BuiltinDerive($func))),
@@ -94,42 +99,41 @@ macro_rules! derive_traits {
 }
 
 derive_traits! {
-    "Clone" => clone::expand_deriving_clone,
+    [None]
+    Clone => clone::expand_deriving_clone,
 
-    "Hash" => hash::expand_deriving_hash,
+    [None]
+    Hash => hash::expand_deriving_hash,
 
-    "RustcEncodable" => encodable::expand_deriving_rustc_encodable,
+    [None]
+    RustcEncodable => encodable::expand_deriving_rustc_encodable,
 
-    "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
+    [None]
+    RustcDecodable => decodable::expand_deriving_rustc_decodable,
 
-    "PartialEq" => partial_eq::expand_deriving_partial_eq,
-    "Eq" => eq::expand_deriving_eq,
-    "PartialOrd" => partial_ord::expand_deriving_partial_ord,
-    "Ord" => ord::expand_deriving_ord,
+    [None]
+    PartialEq => partial_eq::expand_deriving_partial_eq,
+    [None]
+    Eq => eq::expand_deriving_eq,
+    [None]
+    PartialOrd => partial_ord::expand_deriving_partial_ord,
+    [None]
+    Ord => ord::expand_deriving_ord,
 
-    "Debug" => debug::expand_deriving_debug,
+    [None]
+    Debug => debug::expand_deriving_debug,
 
-    "Default" => default::expand_deriving_default,
+    [None]
+    Default => default::expand_deriving_default,
 
-    "Copy" => bounds::expand_deriving_copy,
+    [None]
+    Copy => bounds::expand_deriving_copy,
 
     // deprecated
-    "Encodable" => encodable::expand_deriving_encodable,
-    "Decodable" => decodable::expand_deriving_decodable,
-}
-
-#[inline] // because `name` is a compile-time constant
-fn warn_if_deprecated(ecx: &mut ExtCtxt<'_>, sp: Span, name: &str) {
-    if let Some(replacement) = match name {
-        "Encodable" => Some("RustcEncodable"),
-        "Decodable" => Some("RustcDecodable"),
-        _ => None,
-    } {
-        ecx.span_warn(sp,
-                      &format!("derive({}) is deprecated in favor of derive({})",
-                               name,
-                               replacement));
-    }
+    [Some("derive(Encodable) is deprecated in favor of derive(RustcEncodable)")]
+    Encodable => encodable::expand_deriving_encodable,
+    [Some("derive(Decodable) is deprecated in favor of derive(RustcDecodable)")]
+    Decodable => decodable::expand_deriving_decodable,
 }
 
 /// Construct a name for the inner type parameter that can't collide with any type parameters of
diff --git a/src/libsyntax_ext/format.rs b/src/libsyntax_ext/format.rs
index a5f96559ca8..c3dbd48cc6e 100644
--- a/src/libsyntax_ext/format.rs
+++ b/src/libsyntax_ext/format.rs
@@ -9,7 +9,6 @@ use errors::Applicability;
 use syntax::ast;
 use syntax::ext::base::{self, *};
 use syntax::ext::build::AstBuilder;
-use syntax::feature_gate;
 use syntax::parse::token;
 use syntax::ptr::P;
 use syntax::symbol::{Symbol, sym};
@@ -686,14 +685,16 @@ impl<'a, 'b> Context<'a, 'b> {
     }
 }
 
-pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt<'_>,
-                               mut sp: Span,
-                               tts: &[tokenstream::TokenTree])
-                               -> Box<dyn base::MacResult + 'cx> {
+fn expand_format_args_impl<'cx>(
+    ecx: &'cx mut ExtCtxt<'_>,
+    mut sp: Span,
+    tts: &[tokenstream::TokenTree],
+    nl: bool,
+) -> Box<dyn base::MacResult + 'cx> {
     sp = sp.apply_mark(ecx.current_expansion.mark);
     match parse_args(ecx, sp, tts) {
         Ok((efmt, args, names)) => {
-            MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, false))
+            MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, nl))
         }
         Err(mut err) => {
             err.emit();
@@ -702,34 +703,20 @@ pub fn expand_format_args<'cx>(ecx: &'cx mut ExtCtxt<'_>,
     }
 }
 
+pub fn expand_format_args<'cx>(
+    ecx: &'cx mut ExtCtxt<'_>,
+    sp: Span,
+    tts: &[tokenstream::TokenTree],
+) -> Box<dyn base::MacResult + 'cx> {
+    expand_format_args_impl(ecx, sp, tts, false)
+}
+
 pub fn expand_format_args_nl<'cx>(
     ecx: &'cx mut ExtCtxt<'_>,
-    mut sp: Span,
+    sp: Span,
     tts: &[tokenstream::TokenTree],
 ) -> Box<dyn base::MacResult + 'cx> {
-    //if !ecx.ecfg.enable_allow_internal_unstable() {
-
-    // For some reason, the only one that actually works for `println` is the first check
-    if !sp.allows_unstable(sym::format_args_nl) // the span is marked `#[allow_insternal_unsable]`
-        && !ecx.ecfg.enable_allow_internal_unstable()  // NOTE: when is this enabled?
-        && !ecx.ecfg.enable_format_args_nl()  // enabled using `#[feature(format_args_nl]`
-    {
-        feature_gate::emit_feature_err(&ecx.parse_sess,
-                                       sym::format_args_nl,
-                                       sp,
-                                       feature_gate::GateIssue::Language,
-                                       feature_gate::EXPLAIN_FORMAT_ARGS_NL);
-    }
-    sp = sp.apply_mark(ecx.current_expansion.mark);
-    match parse_args(ecx, sp, tts) {
-        Ok((efmt, args, names)) => {
-            MacEager::expr(expand_preparsed_format_args(ecx, sp, efmt, args, names, true))
-        }
-        Err(mut err) => {
-            err.emit();
-            DummyResult::expr(sp)
-        }
-    }
+    expand_format_args_impl(ecx, sp, tts, true)
 }
 
 /// Take the various parts of `format_args!(efmt, args..., name=names...)`
diff --git a/src/libsyntax_ext/global_asm.rs b/src/libsyntax_ext/global_asm.rs
index 5220143a3cc..112192fac5d 100644
--- a/src/libsyntax_ext/global_asm.rs
+++ b/src/libsyntax_ext/global_asm.rs
@@ -13,27 +13,15 @@ use errors::DiagnosticBuilder;
 use syntax::ast;
 use syntax::source_map::respan;
 use syntax::ext::base::{self, *};
-use syntax::feature_gate;
 use syntax::parse::token;
 use syntax::ptr::P;
-use syntax::symbol::{Symbol, sym};
 use syntax_pos::Span;
 use syntax::tokenstream;
 use smallvec::smallvec;
 
-pub const MACRO: Symbol = sym::global_asm;
-
 pub fn expand_global_asm<'cx>(cx: &'cx mut ExtCtxt<'_>,
                               sp: Span,
                               tts: &[tokenstream::TokenTree]) -> Box<dyn base::MacResult + 'cx> {
-    if !cx.ecfg.enable_global_asm() {
-        feature_gate::emit_feature_err(&cx.parse_sess,
-                                       MACRO,
-                                       sp,
-                                       feature_gate::GateIssue::Language,
-                                       feature_gate::EXPLAIN_GLOBAL_ASM);
-    }
-
     match parse_global_asm(cx, sp, tts) {
         Ok(Some(global_asm)) => {
             MacEager::items(smallvec![P(ast::Item {
diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs
index 77b69ddd303..62530f4fe7b 100644
--- a/src/libsyntax_ext/lib.rs
+++ b/src/libsyntax_ext/lib.rs
@@ -41,12 +41,29 @@ pub mod proc_macro_impl;
 
 use rustc_data_structures::sync::Lrc;
 use syntax::ast;
-
+use syntax::attr::Stability;
 use syntax::ext::base::MacroExpanderFn;
 use syntax::ext::base::{NamedSyntaxExtension, SyntaxExtension, SyntaxExtensionKind};
 use syntax::edition::Edition;
 use syntax::symbol::{sym, Symbol};
 
+const EXPLAIN_ASM: &str =
+    "inline assembly is not stable enough for use and is subject to change";
+const EXPLAIN_GLOBAL_ASM: &str =
+    "`global_asm!` is not stable enough for use and is subject to change";
+const EXPLAIN_CUSTOM_TEST_FRAMEWORKS: &str =
+    "custom test frameworks are an unstable feature";
+const EXPLAIN_LOG_SYNTAX: &str =
+    "`log_syntax!` is not stable enough for use and is subject to change";
+const EXPLAIN_CONCAT_IDENTS: &str =
+    "`concat_idents` is not stable enough for use and is subject to change";
+const EXPLAIN_FORMAT_ARGS_NL: &str =
+    "`format_args_nl` is only for internal language use and is subject to change";
+const EXPLAIN_TRACE_MACROS: &str =
+    "`trace_macros` is not stable enough for use and is subject to change";
+const EXPLAIN_UNSTABLE_COLUMN: &str =
+    "internal implementation detail of the `column` macro";
+
 pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
                          user_exts: Vec<NamedSyntaxExtension>,
                          edition: Edition) {
@@ -57,23 +74,27 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
     };
     macro_rules! register {
         ($( $name:ident: $f:expr, )*) => { $(
-            register(Symbol::intern(stringify!($name)), SyntaxExtension::default(
+            register(sym::$name, SyntaxExtension::default(
                 SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)), edition
             ));
         )* }
     }
-    macro_rules! register_attr {
-        ($( $name:ident: $f:expr, )*) => { $(
-            register(Symbol::intern(stringify!($name)), SyntaxExtension::default(
-                SyntaxExtensionKind::LegacyAttr(Box::new($f)), edition
-            ));
+    macro_rules! register_unstable {
+        ($( [$feature:expr, $reason:expr, $issue:expr] $name:ident: $f:expr, )*) => { $(
+            register(sym::$name, SyntaxExtension {
+                stability: Some(Stability::unstable(
+                    $feature, Some(Symbol::intern($reason)), $issue
+                )),
+                ..SyntaxExtension::default(
+                    SyntaxExtensionKind::LegacyBang(Box::new($f as MacroExpanderFn)), edition
+                )
+            });
         )* }
     }
 
     use syntax::ext::source_util::*;
     register! {
         line: expand_line,
-        __rust_unstable_column: expand_column_gated,
         column: expand_column,
         file: expand_file,
         stringify: expand_stringify,
@@ -81,35 +102,60 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
         include_str: expand_include_str,
         include_bytes: expand_include_bytes,
         module_path: expand_mod,
-
-        asm: asm::expand_asm,
-        global_asm: global_asm::expand_global_asm,
         cfg: cfg::expand_cfg,
         concat: concat::expand_syntax_ext,
-        concat_idents: concat_idents::expand_syntax_ext,
         env: env::expand_env,
         option_env: env::expand_option_env,
-        log_syntax: log_syntax::expand_syntax_ext,
-        trace_macros: trace_macros::expand_trace_macros,
         compile_error: compile_error::expand_compile_error,
         assert: assert::expand_assert,
     }
 
-    register_attr! {
-        test_case: test_case::expand,
-        test: test::expand_test,
-        bench: test::expand_bench,
+    register_unstable! {
+        [sym::__rust_unstable_column, EXPLAIN_UNSTABLE_COLUMN, 0]
+        __rust_unstable_column: expand_column,
+        [sym::asm, EXPLAIN_ASM, 29722]
+        asm: asm::expand_asm,
+        [sym::global_asm, EXPLAIN_GLOBAL_ASM, 35119]
+        global_asm: global_asm::expand_global_asm,
+        [sym::concat_idents, EXPLAIN_CONCAT_IDENTS, 29599]
+        concat_idents: concat_idents::expand_syntax_ext,
+        [sym::log_syntax, EXPLAIN_LOG_SYNTAX, 29598]
+        log_syntax: log_syntax::expand_syntax_ext,
+        [sym::trace_macros, EXPLAIN_TRACE_MACROS, 29598]
+        trace_macros: trace_macros::expand_trace_macros,
     }
 
+    register(sym::test_case, SyntaxExtension {
+        stability: Some(Stability::unstable(
+            sym::custom_test_frameworks,
+            Some(Symbol::intern(EXPLAIN_CUSTOM_TEST_FRAMEWORKS)),
+            50297,
+        )),
+        ..SyntaxExtension::default(
+            SyntaxExtensionKind::LegacyAttr(Box::new(test_case::expand)), edition
+        )
+    });
+    register(sym::test, SyntaxExtension::default(
+        SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_test)), edition
+    ));
+    register(sym::bench, SyntaxExtension::default(
+        SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_bench)), edition
+    ));
+
     // format_args uses `unstable` things internally.
     let allow_internal_unstable = Some([sym::fmt_internals][..].into());
-    register(Symbol::intern("format_args"), SyntaxExtension {
+    register(sym::format_args, SyntaxExtension {
         allow_internal_unstable: allow_internal_unstable.clone(),
         ..SyntaxExtension::default(
             SyntaxExtensionKind::LegacyBang(Box::new(format::expand_format_args)), edition
         )
     });
     register(sym::format_args_nl, SyntaxExtension {
+        stability: Some(Stability::unstable(
+            sym::format_args_nl,
+            Some(Symbol::intern(EXPLAIN_FORMAT_ARGS_NL)),
+            0,
+        )),
         allow_internal_unstable,
         ..SyntaxExtension::default(
             SyntaxExtensionKind::LegacyBang(Box::new(format::expand_format_args_nl)), edition
diff --git a/src/libsyntax_ext/log_syntax.rs b/src/libsyntax_ext/log_syntax.rs
index 1be3990837c..cbdfd08b497 100644
--- a/src/libsyntax_ext/log_syntax.rs
+++ b/src/libsyntax_ext/log_syntax.rs
@@ -1,22 +1,12 @@
 use syntax::ext::base;
-use syntax::feature_gate;
 use syntax::print;
 use syntax::tokenstream;
-use syntax::symbol::sym;
 use syntax_pos;
 
-pub fn expand_syntax_ext<'cx>(cx: &'cx mut base::ExtCtxt<'_>,
+pub fn expand_syntax_ext<'cx>(_cx: &'cx mut base::ExtCtxt<'_>,
                               sp: syntax_pos::Span,
                               tts: &[tokenstream::TokenTree])
                               -> Box<dyn base::MacResult + 'cx> {
-    if !cx.ecfg.enable_log_syntax() {
-        feature_gate::emit_feature_err(&cx.parse_sess,
-                                       sym::log_syntax,
-                                       sp,
-                                       feature_gate::GateIssue::Language,
-                                       feature_gate::EXPLAIN_LOG_SYNTAX);
-    }
-
     println!("{}", print::pprust::tts_to_string(tts));
 
     // any so that `log_syntax` can be invoked as an expression and item.
diff --git a/src/libsyntax_ext/proc_macro_server.rs b/src/libsyntax_ext/proc_macro_server.rs
index c9d99e5831a..e5027354527 100644
--- a/src/libsyntax_ext/proc_macro_server.rs
+++ b/src/libsyntax_ext/proc_macro_server.rs
@@ -548,10 +548,10 @@ impl server::Literal for Rustc<'_> {
         self.lit(token::Float, Symbol::intern(n), None)
     }
     fn f32(&mut self, n: &str) -> Self::Literal {
-        self.lit(token::Float, Symbol::intern(n), Some(Symbol::intern("f32")))
+        self.lit(token::Float, Symbol::intern(n), Some(sym::f32))
     }
     fn f64(&mut self, n: &str) -> Self::Literal {
-        self.lit(token::Float, Symbol::intern(n), Some(Symbol::intern("f64")))
+        self.lit(token::Float, Symbol::intern(n), Some(sym::f64))
     }
     fn string(&mut self, string: &str) -> Self::Literal {
         let mut escaped = String::new();
diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs
index 6e3bc05b65e..186673c142f 100644
--- a/src/libsyntax_ext/test_case.rs
+++ b/src/libsyntax_ext/test_case.rs
@@ -17,7 +17,6 @@ use syntax::source_map::respan;
 use syntax::symbol::sym;
 use syntax_pos::Span;
 use syntax::source_map::{ExpnInfo, MacroAttribute};
-use syntax::feature_gate;
 
 pub fn expand(
     ecx: &mut ExtCtxt<'_>,
@@ -25,14 +24,6 @@ pub fn expand(
     _meta_item: &ast::MetaItem,
     anno_item: Annotatable
 ) -> Vec<Annotatable> {
-    if !ecx.ecfg.enable_custom_test_frameworks() {
-        feature_gate::emit_feature_err(&ecx.parse_sess,
-                                       sym::custom_test_frameworks,
-                                       attr_sp,
-                                       feature_gate::GateIssue::Language,
-                                       feature_gate::EXPLAIN_CUSTOM_TEST_FRAMEWORKS);
-    }
-
     if !ecx.ecfg.should_test { return vec![]; }
 
     let sp = {
diff --git a/src/libsyntax_ext/trace_macros.rs b/src/libsyntax_ext/trace_macros.rs
index 512513e9b41..0dce8a36f4c 100644
--- a/src/libsyntax_ext/trace_macros.rs
+++ b/src/libsyntax_ext/trace_macros.rs
@@ -1,6 +1,5 @@
 use syntax::ext::base::{self, ExtCtxt};
-use syntax::feature_gate;
-use syntax::symbol::{kw, sym};
+use syntax::symbol::kw;
 use syntax_pos::Span;
 use syntax::tokenstream::TokenTree;
 
@@ -8,14 +7,6 @@ pub fn expand_trace_macros(cx: &mut ExtCtxt<'_>,
                            sp: Span,
                            tt: &[TokenTree])
                            -> Box<dyn base::MacResult + 'static> {
-    if !cx.ecfg.enable_trace_macros() {
-        feature_gate::emit_feature_err(&cx.parse_sess,
-                                       sym::trace_macros,
-                                       sp,
-                                       feature_gate::GateIssue::Language,
-                                       feature_gate::EXPLAIN_TRACE_MACROS);
-    }
-
     match tt {
         [TokenTree::Token(token)] if token.is_keyword(kw::True) => {
             cx.set_trace_macros(true);
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index 410f4b36b67..8bb622a6855 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -141,6 +141,7 @@ symbols! {
         ArgumentV1,
         arm_target_feature,
         asm,
+        assert,
         associated_consts,
         associated_type_bounds,
         associated_type_defaults,
@@ -184,8 +185,10 @@ symbols! {
         cmp,
         cmpxchg16b_target_feature,
         cold,
+        column,
         compile_error,
         compiler_builtins,
+        concat,
         concat_idents,
         conservative_impl_trait,
         console,
@@ -203,6 +206,7 @@ symbols! {
         contents,
         context,
         convert,
+        Copy,
         copy_closures,
         core,
         core_intrinsics,
@@ -217,8 +221,10 @@ symbols! {
         custom_inner_attributes,
         custom_test_frameworks,
         c_variadic,
+        Debug,
         declare_lint_pass,
         decl_macro,
+        Decodable,
         Default,
         default_lib_allocator,
         default_type_parameter_fallback,
@@ -253,9 +259,12 @@ symbols! {
         eh_personality,
         eh_unwind_resume,
         enable,
+        Encodable,
+        env,
         eq,
         err,
         Err,
+        Eq,
         Equal,
         except,
         exclusive_range_pattern,
@@ -284,6 +293,7 @@ symbols! {
         fmt_internals,
         fn_must_use,
         forbid,
+        format_args,
         format_args_nl,
         from,
         From,
@@ -335,6 +345,8 @@ symbols! {
         index_mut,
         in_band_lifetimes,
         include,
+        include_bytes,
+        include_str,
         inclusive_range_syntax,
         infer_outlives_requirements,
         infer_static_outlives_requirements,
@@ -363,6 +375,7 @@ symbols! {
         lhs,
         lib,
         lifetime,
+        line,
         link,
         linkage,
         link_args,
@@ -402,6 +415,7 @@ symbols! {
         mips_target_feature,
         mmx_target_feature,
         module,
+        module_path,
         more_struct_aliases,
         movbe_target_feature,
         must_use,
@@ -447,6 +461,7 @@ symbols! {
         optin_builtin_traits,
         option,
         Option,
+        option_env,
         opt_out_copy,
         or,
         Ord,
@@ -462,6 +477,7 @@ symbols! {
         parent_trait,
         partial_cmp,
         param_attrs,
+        PartialEq,
         PartialOrd,
         passes,
         pat,
@@ -532,6 +548,8 @@ symbols! {
         rust_2018_preview,
         rust_begin_unwind,
         rustc,
+        RustcDecodable,
+        RustcEncodable,
         rustc_allocator,
         rustc_allocator_nounwind,
         rustc_allow_const_fn_ptr,
@@ -591,7 +609,6 @@ symbols! {
         _Self,
         self_in_typedefs,
         self_struct_ctor,
-        Send,
         should_panic,
         simd,
         simd_ffi,
@@ -613,6 +630,7 @@ symbols! {
         static_recursion,
         std,
         str,
+        stringify,
         stmt,
         stmt_expr_attributes,
         stop_after_dataflow,
diff --git a/src/test/run-pass/macros/macro-stability.rs b/src/test/run-pass/macros/macro-stability.rs
index b471aa655e9..817bddf6956 100644
--- a/src/test/run-pass/macros/macro-stability.rs
+++ b/src/test/run-pass/macros/macro-stability.rs
@@ -1,7 +1,7 @@
 // run-pass
 // aux-build:unstable-macros.rs
 
-#![feature(unstable_macros)]
+#![feature(unstable_macros, local_unstable)]
 
 #[macro_use] extern crate unstable_macros;
 
diff --git a/src/test/ui-fulldeps/deprecated-derive.stderr b/src/test/ui-fulldeps/deprecated-derive.stderr
index 27762910e6a..9afb3a35cb4 100644
--- a/src/test/ui-fulldeps/deprecated-derive.stderr
+++ b/src/test/ui-fulldeps/deprecated-derive.stderr
@@ -1,6 +1,8 @@
-warning: derive(Encodable) is deprecated in favor of derive(RustcEncodable)
+warning: use of deprecated item 'Encodable': derive(Encodable) is deprecated in favor of derive(RustcEncodable)
   --> $DIR/deprecated-derive.rs:8:10
    |
 LL | #[derive(Encodable)]
    |          ^^^^^^^^^
+   |
+   = note: #[warn(deprecated)] on by default
 
diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr
index ccaf34f0169..30a7582a92b 100644
--- a/src/test/ui/feature-gates/feature-gate-asm.stderr
+++ b/src/test/ui/feature-gates/feature-gate-asm.stderr
@@ -1,4 +1,4 @@
-error[E0658]: inline assembly is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'asm': inline assembly is not stable enough for use and is subject to change
   --> $DIR/feature-gate-asm.rs:3:9
    |
 LL |         asm!("");
diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr
index cafe2be9d0b..8f4c6806a97 100644
--- a/src/test/ui/feature-gates/feature-gate-asm2.stderr
+++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr
@@ -1,4 +1,4 @@
-error[E0658]: inline assembly is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'asm': inline assembly is not stable enough for use and is subject to change
   --> $DIR/feature-gate-asm2.rs:5:26
    |
 LL |         println!("{:?}", asm!(""));
diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents.stderr
index be8c727e2be..2a1e5f54592 100644
--- a/src/test/ui/feature-gates/feature-gate-concat_idents.stderr
+++ b/src/test/ui/feature-gates/feature-gate-concat_idents.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `concat_idents` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` is not stable enough for use and is subject to change
   --> $DIR/feature-gate-concat_idents.rs:5:13
    |
 LL |     let a = concat_idents!(X, Y_1);
@@ -7,7 +7,7 @@ LL |     let a = concat_idents!(X, Y_1);
    = note: for more information, see https://github.com/rust-lang/rust/issues/29599
    = help: add #![feature(concat_idents)] to the crate attributes to enable
 
-error[E0658]: `concat_idents` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` is not stable enough for use and is subject to change
   --> $DIR/feature-gate-concat_idents.rs:6:13
    |
 LL |     let b = concat_idents!(X, Y_2);
diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr
index 864ee63b201..0dc6c13734e 100644
--- a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr
+++ b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `concat_idents` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` is not stable enough for use and is subject to change
   --> $DIR/feature-gate-concat_idents2.rs:4:5
    |
 LL |     concat_idents!(a, b);
diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr
index cb8725ab566..543570f0afc 100644
--- a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr
+++ b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `concat_idents` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` is not stable enough for use and is subject to change
   --> $DIR/feature-gate-concat_idents3.rs:7:20
    |
 LL |     assert_eq!(10, concat_idents!(X, Y_1));
@@ -7,7 +7,7 @@ LL |     assert_eq!(10, concat_idents!(X, Y_1));
    = note: for more information, see https://github.com/rust-lang/rust/issues/29599
    = help: add #![feature(concat_idents)] to the crate attributes to enable
 
-error[E0658]: `concat_idents` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` is not stable enough for use and is subject to change
   --> $DIR/feature-gate-concat_idents3.rs:8:20
    |
 LL |     assert_eq!(20, concat_idents!(X, Y_2));
diff --git a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.rs b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.rs
index 0a200497939..83bb153ba08 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.rs
+++ b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.rs
@@ -1,3 +1,6 @@
 #![test_runner(main)] //~ ERROR custom test frameworks are an unstable feature
 
+#[test_case] //~ ERROR custom test frameworks are an unstable feature
+fn f() {}
+
 fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr
index e288af54cb2..31ff7aebe3a 100644
--- a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr
+++ b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr
@@ -1,3 +1,12 @@
+error[E0658]: use of unstable library feature 'custom_test_frameworks': custom test frameworks are an unstable feature
+  --> $DIR/feature-gate-custom_test_frameworks.rs:3:1
+   |
+LL | #[test_case]
+   | ^^^^^^^^^^^^
+   |
+   = note: for more information, see https://github.com/rust-lang/rust/issues/50297
+   = help: add #![feature(custom_test_frameworks)] to the crate attributes to enable
+
 error[E0658]: custom test frameworks are an unstable feature
   --> $DIR/feature-gate-custom_test_frameworks.rs:1:1
    |
@@ -7,6 +16,6 @@ LL | #![test_runner(main)]
    = note: for more information, see https://github.com/rust-lang/rust/issues/50297
    = help: add #![feature(custom_test_frameworks)] to the crate attributes to enable
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr b/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr
index 58d2c790ffe..5cf48d8749c 100644
--- a/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr
+++ b/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `format_args_nl` is only for internal language use and is subject to change
+error[E0658]: use of unstable library feature 'format_args_nl': `format_args_nl` is only for internal language use and is subject to change
   --> $DIR/feature-gate-format_args_nl.rs:2:5
    |
 LL |     format_args_nl!("");
diff --git a/src/test/ui/feature-gates/feature-gate-global_asm.stderr b/src/test/ui/feature-gates/feature-gate-global_asm.stderr
index 7d8abac3990..c65f8d87a6a 100644
--- a/src/test/ui/feature-gates/feature-gate-global_asm.stderr
+++ b/src/test/ui/feature-gates/feature-gate-global_asm.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `global_asm!` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'global_asm': `global_asm!` is not stable enough for use and is subject to change
   --> $DIR/feature-gate-global_asm.rs:1:1
    |
 LL | global_asm!("");
diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax.stderr b/src/test/ui/feature-gates/feature-gate-log_syntax.stderr
index 67bd48d3bed..f6a07616c53 100644
--- a/src/test/ui/feature-gates/feature-gate-log_syntax.stderr
+++ b/src/test/ui/feature-gates/feature-gate-log_syntax.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `log_syntax!` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'log_syntax': `log_syntax!` is not stable enough for use and is subject to change
   --> $DIR/feature-gate-log_syntax.rs:2:5
    |
 LL |     log_syntax!()
diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr
index ff0fa343c84..cfc2beb8087 100644
--- a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr
+++ b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `log_syntax!` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'log_syntax': `log_syntax!` is not stable enough for use and is subject to change
   --> $DIR/feature-gate-log_syntax2.rs:4:22
    |
 LL |     println!("{:?}", log_syntax!());
diff --git a/src/test/ui/feature-gates/feature-gate-trace_macros.stderr b/src/test/ui/feature-gates/feature-gate-trace_macros.stderr
index bcce31d873b..e08b173ae84 100644
--- a/src/test/ui/feature-gates/feature-gate-trace_macros.stderr
+++ b/src/test/ui/feature-gates/feature-gate-trace_macros.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `trace_macros` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is not stable enough for use and is subject to change
   --> $DIR/feature-gate-trace_macros.rs:2:5
    |
 LL |     trace_macros!(true);
diff --git a/src/test/ui/macros/auxiliary/deprecated-macros.rs b/src/test/ui/macros/auxiliary/deprecated-macros.rs
new file mode 100644
index 00000000000..657a7252a36
--- /dev/null
+++ b/src/test/ui/macros/auxiliary/deprecated-macros.rs
@@ -0,0 +1,3 @@
+#[deprecated(since = "1.0.0", note = "deprecation note")]
+#[macro_export]
+macro_rules! deprecated_macro{ () => () }
diff --git a/src/test/ui/macros/auxiliary/unstable-macros.rs b/src/test/ui/macros/auxiliary/unstable-macros.rs
index b8d580702c9..e928dc705d7 100644
--- a/src/test/ui/macros/auxiliary/unstable-macros.rs
+++ b/src/test/ui/macros/auxiliary/unstable-macros.rs
@@ -1,6 +1,16 @@
+#![feature(decl_macro)]
 #![feature(staged_api)]
 #![stable(feature = "unit_test", since = "1.0.0")]
 
 #[unstable(feature = "unstable_macros", issue = "0")]
 #[macro_export]
 macro_rules! unstable_macro{ () => () }
+
+#[stable(feature = "deprecated_macros", since = "1.0.0")]
+#[rustc_deprecated(since = "1.0.0", reason = "deprecation reason")]
+#[macro_export]
+macro_rules! deprecated_macro{ () => () }
+
+// FIXME: Cannot use a `pub` macro 2.0 in a staged API crate due to reachability issues.
+// #[unstable(feature = "unstable_macros", issue = "0")]
+// pub macro unstable_macro_modern() {}
diff --git a/src/test/ui/macros/macro-deprecation.rs b/src/test/ui/macros/macro-deprecation.rs
new file mode 100644
index 00000000000..9636b48c2da
--- /dev/null
+++ b/src/test/ui/macros/macro-deprecation.rs
@@ -0,0 +1,13 @@
+// check-pass
+// aux-build:deprecated-macros.rs
+
+#[macro_use] extern crate deprecated_macros;
+
+#[deprecated(since = "1.0.0", note = "local deprecation note")]
+#[macro_export]
+macro_rules! local_deprecated{ () => () }
+
+fn main() {
+    local_deprecated!(); //~ WARN use of deprecated item 'local_deprecated': local deprecation note
+    deprecated_macro!(); //~ WARN use of deprecated item 'deprecated_macro': deprecation note
+}
diff --git a/src/test/ui/macros/macro-deprecation.stderr b/src/test/ui/macros/macro-deprecation.stderr
new file mode 100644
index 00000000000..e5f4df52237
--- /dev/null
+++ b/src/test/ui/macros/macro-deprecation.stderr
@@ -0,0 +1,14 @@
+warning: use of deprecated item 'local_deprecated': local deprecation note
+  --> $DIR/macro-deprecation.rs:11:5
+   |
+LL |     local_deprecated!();
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(deprecated)] on by default
+
+warning: use of deprecated item 'deprecated_macro': deprecation note
+  --> $DIR/macro-deprecation.rs:12:5
+   |
+LL |     deprecated_macro!();
+   |     ^^^^^^^^^^^^^^^^^^^^
+
diff --git a/src/test/ui/macros/macro-stability.rs b/src/test/ui/macros/macro-stability.rs
index 7d1ee6a43b6..ab927e419b4 100644
--- a/src/test/ui/macros/macro-stability.rs
+++ b/src/test/ui/macros/macro-stability.rs
@@ -1,12 +1,28 @@
 // aux-build:unstable-macros.rs
 
+#![feature(decl_macro)]
 #![feature(staged_api)]
 #[macro_use] extern crate unstable_macros;
 
 #[unstable(feature = "local_unstable", issue = "0")]
 macro_rules! local_unstable { () => () }
 
+#[unstable(feature = "local_unstable", issue = "0")]
+macro local_unstable_modern() {}
+
+#[stable(feature = "deprecated_macros", since = "1.0.0")]
+#[rustc_deprecated(since = "1.0.0", reason = "local deprecation reason")]
+#[macro_export]
+macro_rules! local_deprecated{ () => () }
+
 fn main() {
-    local_unstable!();
-    unstable_macro!(); //~ ERROR: macro unstable_macro! is unstable
+    local_unstable!(); //~ ERROR use of unstable library feature 'local_unstable'
+    local_unstable_modern!(); //~ ERROR use of unstable library feature 'local_unstable'
+    unstable_macro!(); //~ ERROR use of unstable library feature 'unstable_macros'
+    // unstable_macro_modern!(); // ERROR use of unstable library feature 'unstable_macros'
+
+    deprecated_macro!();
+    //~^ WARN use of deprecated item 'deprecated_macro': deprecation reason
+    local_deprecated!();
+    //~^ WARN use of deprecated item 'local_deprecated': local deprecation reason
 }
diff --git a/src/test/ui/macros/macro-stability.stderr b/src/test/ui/macros/macro-stability.stderr
index a0e0c351a48..88edadc3811 100644
--- a/src/test/ui/macros/macro-stability.stderr
+++ b/src/test/ui/macros/macro-stability.stderr
@@ -1,11 +1,41 @@
-error[E0658]: macro unstable_macro! is unstable
-  --> $DIR/macro-stability.rs:11:5
+error[E0658]: use of unstable library feature 'local_unstable'
+  --> $DIR/macro-stability.rs:19:5
+   |
+LL |     local_unstable!();
+   |     ^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(local_unstable)] to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'local_unstable'
+  --> $DIR/macro-stability.rs:20:5
+   |
+LL |     local_unstable_modern!();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(local_unstable)] to the crate attributes to enable
+
+error[E0658]: use of unstable library feature 'unstable_macros'
+  --> $DIR/macro-stability.rs:21:5
    |
 LL |     unstable_macro!();
    |     ^^^^^^^^^^^^^^^^^^
    |
    = help: add #![feature(unstable_macros)] to the crate attributes to enable
 
-error: aborting due to previous error
+warning: use of deprecated item 'deprecated_macro': deprecation reason
+  --> $DIR/macro-stability.rs:24:5
+   |
+LL |     deprecated_macro!();
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: #[warn(deprecated)] on by default
+
+warning: use of deprecated item 'local_deprecated': local deprecation reason
+  --> $DIR/macro-stability.rs:26:5
+   |
+LL |     local_deprecated!();
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/rust-unstable-column-gated.rs b/src/test/ui/rust-unstable-column-gated.rs
index ed5e6f2489c..053806ead2d 100644
--- a/src/test/ui/rust-unstable-column-gated.rs
+++ b/src/test/ui/rust-unstable-column-gated.rs
@@ -1,4 +1,4 @@
 fn main() {
     println!("{}", __rust_unstable_column!());
-    //~^ERROR the __rust_unstable_column macro is unstable
+    //~^ ERROR use of unstable library feature '__rust_unstable_column'
 }
diff --git a/src/test/ui/rust-unstable-column-gated.stderr b/src/test/ui/rust-unstable-column-gated.stderr
index b9f1df2bcc9..70b3654b5af 100644
--- a/src/test/ui/rust-unstable-column-gated.stderr
+++ b/src/test/ui/rust-unstable-column-gated.stderr
@@ -1,8 +1,11 @@
-error: the __rust_unstable_column macro is unstable
+error[E0658]: use of unstable library feature '__rust_unstable_column': internal implementation detail of the `column` macro
   --> $DIR/rust-unstable-column-gated.rs:2:20
    |
 LL |     println!("{}", __rust_unstable_column!());
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: add #![feature(__rust_unstable_column)] to the crate attributes to enable
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0658`.
diff --git a/src/test/ui/trace_macros-gate.stderr b/src/test/ui/trace_macros-gate.stderr
index e0ffcfe295f..18745e9ab5a 100644
--- a/src/test/ui/trace_macros-gate.stderr
+++ b/src/test/ui/trace_macros-gate.stderr
@@ -1,4 +1,4 @@
-error[E0658]: `trace_macros` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is not stable enough for use and is subject to change
   --> $DIR/trace_macros-gate.rs:4:5
    |
 LL |     trace_macros!();
@@ -13,7 +13,7 @@ error: trace_macros! accepts only `true` or `false`
 LL |     trace_macros!();
    |     ^^^^^^^^^^^^^^^^
 
-error[E0658]: `trace_macros` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is not stable enough for use and is subject to change
   --> $DIR/trace_macros-gate.rs:6:5
    |
 LL |     trace_macros!(true);
@@ -22,7 +22,7 @@ LL |     trace_macros!(true);
    = note: for more information, see https://github.com/rust-lang/rust/issues/29598
    = help: add #![feature(trace_macros)] to the crate attributes to enable
 
-error[E0658]: `trace_macros` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is not stable enough for use and is subject to change
   --> $DIR/trace_macros-gate.rs:7:5
    |
 LL |     trace_macros!(false);
@@ -31,7 +31,7 @@ LL |     trace_macros!(false);
    = note: for more information, see https://github.com/rust-lang/rust/issues/29598
    = help: add #![feature(trace_macros)] to the crate attributes to enable
 
-error[E0658]: `trace_macros` is not stable enough for use and is subject to change
+error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is not stable enough for use and is subject to change
   --> $DIR/trace_macros-gate.rs:10:26
    |
 LL |         ($x: ident) => { trace_macros!($x) }