about summary refs log tree commit diff
diff options
context:
space:
mode:
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-06-22 16:18:05 +0300
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>2019-07-07 13:04:07 +0300
commit1ee0ce82cba66305f03725fb73ad381349a9b8e4 (patch)
treebfa302da7bb973a871d27f726e2c3a95e07ba668
parent0817fc6c6cd880c51318d476de9ecb43327e12b1 (diff)
downloadrust-1ee0ce82cba66305f03725fb73ad381349a9b8e4.tar.gz
rust-1ee0ce82cba66305f03725fb73ad381349a9b8e4.zip
syntax: Migrate built-in macros to the regular stability checking
-rw-r--r--src/librustc_resolve/lib.rs8
-rw-r--r--src/librustc_resolve/macros.rs5
-rw-r--r--src/libserialize/json.rs2
-rw-r--r--src/libsyntax/attr/builtin.rs13
-rw-r--r--src/libsyntax/ext/expand.rs36
-rw-r--r--src/libsyntax/ext/source_util.rs12
-rw-r--r--src/libsyntax/feature_gate.rs22
-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.rs34
-rw-r--r--src/libsyntax_ext/format.rs47
-rw-r--r--src/libsyntax_ext/global_asm.rs12
-rw-r--r--src/libsyntax_ext/lib.rs80
-rw-r--r--src/libsyntax_ext/log_syntax.rs12
-rw-r--r--src/libsyntax_ext/test_case.rs9
-rw-r--r--src/libsyntax_ext/trace_macros.rs11
-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-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/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
32 files changed, 161 insertions, 209 deletions
diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs
index d2a9627201b..66410482cc6 100644
--- a/src/librustc_resolve/lib.rs
+++ b/src/librustc_resolve/lib.rs
@@ -1684,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.
@@ -1922,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,6 +2013,10 @@ impl<'a> Resolver<'a> {
             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 c65208b8ed2..6d669aafc81 100644
--- a/src/librustc_resolve/macros.rs
+++ b/src/librustc_resolve/macros.rs
@@ -1013,9 +1013,8 @@ 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, features) = (stability.feature, self.session.features_untracked());
-                if !span.allows_unstable(feature) &&
-                   features.declared_lib_features.iter().all(|(feat, _)| *feat != feature) {
+                let feature = stability.feature;
+                if !self.active_features.contains(&feature) && !span.allows_unstable(feature) {
                     stability::report_unstable(self.session, feature, reason, issue, span);
                 }
             }
diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs
index 726306d60ce..77947a4be7f 100644
--- a/src/libserialize/json.rs
+++ b/src/libserialize/json.rs
@@ -103,6 +103,7 @@
 //!
 //! ```rust
 //! # #![feature(rustc_private)]
+//! # #![allow(deprecated)]
 //! extern crate serialize;
 //! use serialize::json::{self, ToJson, Json};
 //!
@@ -143,6 +144,7 @@
 //!
 //! ```rust
 //! # #![feature(rustc_private)]
+//! # #![allow(deprecated)]
 //! extern crate serialize;
 //! use std::collections::BTreeMap;
 //! use serialize::json::{self, Json, ToJson};
diff --git a/src/libsyntax/attr/builtin.rs b/src/libsyntax/attr/builtin.rs
index 9b411981ed3..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 {
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index 6be5988d03b..74ef5cbe917 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -487,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,
@@ -919,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,
@@ -1432,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 {
@@ -1458,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/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_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..f7889b9cac0 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,7 +61,7 @@ impl MultiItemModifier for BuiltinDerive {
 }
 
 macro_rules! derive_traits {
-    ($( $name:expr => $func:path, )+) => {
+    ($( [$deprecation:expr] $name:expr => $func:path, )+) => {
         pub fn is_builtin_trait(name: ast::Name) -> bool {
             match &*name.as_str() {
                 $( $name )|+ => true,
@@ -81,6 +82,10 @@ macro_rules! derive_traits {
                 resolver.add_builtin(
                     ast::Ident::with_empty_ctxt(Symbol::intern($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,44 +99,43 @@ macro_rules! derive_traits {
 }
 
 derive_traits! {
+    [None]
     "Clone" => clone::expand_deriving_clone,
 
+    [None]
     "Hash" => hash::expand_deriving_hash,
 
+    [None]
     "RustcEncodable" => encodable::expand_deriving_rustc_encodable,
 
+    [None]
     "RustcDecodable" => decodable::expand_deriving_rustc_decodable,
 
+    [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,
 
+    [None]
     "Debug" => debug::expand_deriving_debug,
 
+    [None]
     "Default" => default::expand_deriving_default,
 
+    [None]
     "Copy" => bounds::expand_deriving_copy,
 
     // deprecated
+    [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,
 }
 
-#[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));
-    }
-}
-
 /// Construct a name for the inner type parameter that can't collide with any type parameters of
 /// the item. This is achieved by starting with a base and then concatenating the names of all
 /// other type parameters.
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..1ca5cc47fa2 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) {
@@ -62,18 +79,22 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
             ));
         )* }
     }
-    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(Symbol::intern(stringify!($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,26 +102,46 @@ 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 {
@@ -110,6 +151,11 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver,
         )
     });
     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/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/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-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/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) }