about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs12
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs16
-rw-r--r--compiler/rustc_attr/src/builtin.rs21
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/cfg.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs3
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/standard_library_imports.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs13
-rw-r--r--compiler/rustc_expand/src/base.rs5
-rw-r--r--compiler/rustc_expand/src/expand.rs21
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs7
-rw-r--r--compiler/rustc_interface/Cargo.toml1
-rw-r--r--compiler/rustc_interface/src/passes.rs35
-rw-r--r--compiler/rustc_interface/src/queries.rs7
-rw-r--r--compiler/rustc_lint/src/builtin.rs2
-rw-r--r--compiler/rustc_lint/src/context.rs3
-rw-r--r--compiler/rustc_lint/src/early.rs3
-rw-r--r--compiler/rustc_lint/src/levels.rs14
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs4
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs7
-rw-r--r--compiler/rustc_middle/src/arena.rs1
-rw-r--r--compiler/rustc_passes/src/stability.rs2
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs2
-rw-r--r--compiler/rustc_resolve/src/lib.rs2
-rw-r--r--compiler/rustc_resolve/src/macros.rs3
-rw-r--r--compiler/rustc_session/src/session.rs20
-rw-r--r--src/librustdoc/clean/inline.rs4
-rw-r--r--src/librustdoc/html/format.rs2
30 files changed, 130 insertions, 93 deletions
diff --git a/Cargo.lock b/Cargo.lock
index de6258502a3..897a4f6adfb 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3805,6 +3805,7 @@ dependencies = [
  "rustc_data_structures",
  "rustc_errors",
  "rustc_expand",
+ "rustc_feature",
  "rustc_fluent_macro",
  "rustc_fs_util",
  "rustc_hir",
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 79fc9e4382f..bd3e676daa4 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -13,6 +13,7 @@ use rustc_ast::*;
 use rustc_ast::{walk_list, StaticItem};
 use rustc_ast_pretty::pprust::{self, State};
 use rustc_data_structures::fx::FxIndexMap;
+use rustc_feature::Features;
 use rustc_macros::Subdiagnostic;
 use rustc_parse::validate_attr;
 use rustc_session::lint::builtin::{
@@ -45,6 +46,7 @@ enum DisallowTildeConstContext<'a> {
 
 struct AstValidator<'a> {
     session: &'a Session,
+    features: &'a Features,
 
     /// The span of the `extern` in an `extern { ... }` block, if any.
     extern_mod: Option<&'a Item>,
@@ -1023,7 +1025,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 }
                 self.check_type_no_bounds(bounds, "this context");
 
-                if self.session.features_untracked().lazy_type_alias {
+                if self.features.lazy_type_alias {
                     if let Err(err) = self.check_type_alias_where_clause_location(ty_alias) {
                         self.err_handler().emit_err(err);
                     }
@@ -1500,9 +1502,15 @@ fn deny_equality_constraints(
     this.err_handler().emit_err(err);
 }
 
-pub fn check_crate(session: &Session, krate: &Crate, lints: &mut LintBuffer) -> bool {
+pub fn check_crate(
+    session: &Session,
+    features: &Features,
+    krate: &Crate,
+    lints: &mut LintBuffer,
+) -> bool {
     let mut validator = AstValidator {
         session,
+        features,
         extern_mod: None,
         in_trait_impl: false,
         in_const_trait_impl: false,
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index c4efad7caf2..10c9c3ef111 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -514,10 +514,10 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
     }
 }
 
-pub fn check_crate(krate: &ast::Crate, sess: &Session) {
-    maybe_stage_features(sess, krate);
-    check_incompatible_features(sess);
-    let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() };
+pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
+    maybe_stage_features(sess, features, krate);
+    check_incompatible_features(sess, features);
+    let mut visitor = PostExpansionVisitor { sess, features };
 
     let spans = sess.parse_sess.gated_spans.spans.borrow();
     macro_rules! gate_all {
@@ -600,12 +600,12 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
     visit::walk_crate(&mut visitor, krate);
 }
 
-fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
+fn maybe_stage_features(sess: &Session, features: &Features, krate: &ast::Crate) {
     // checks if `#![feature]` has been used to enable any lang feature
     // does not check the same for lib features unless there's at least one
     // declared lang feature
     if !sess.opts.unstable_features.is_nightly_build() {
-        let lang_features = &sess.features_untracked().declared_lang_features;
+        let lang_features = &features.declared_lang_features;
         if lang_features.len() == 0 {
             return;
         }
@@ -640,9 +640,7 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
     }
 }
 
-fn check_incompatible_features(sess: &Session) {
-    let features = sess.features_untracked();
-
+fn check_incompatible_features(sess: &Session, features: &Features) {
     let declared_features = features
         .declared_lang_features
         .iter()
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index 6ed5fc77d75..3592287b95c 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -800,18 +800,15 @@ pub struct Deprecation {
 }
 
 /// Finds the deprecation attribute. `None` if none exists.
-pub fn find_deprecation(sess: &Session, attrs: &[Attribute]) -> Option<(Deprecation, Span)> {
-    find_deprecation_generic(sess, attrs.iter())
-}
-
-fn find_deprecation_generic<'a, I>(sess: &Session, attrs_iter: I) -> Option<(Deprecation, Span)>
-where
-    I: Iterator<Item = &'a Attribute>,
-{
+pub fn find_deprecation(
+    sess: &Session,
+    features: &Features,
+    attrs: &[Attribute],
+) -> Option<(Deprecation, Span)> {
     let mut depr: Option<(Deprecation, Span)> = None;
-    let is_rustc = sess.features_untracked().staged_api;
+    let is_rustc = features.staged_api;
 
-    'outer: for attr in attrs_iter {
+    'outer: for attr in attrs {
         if !attr.has_name(sym::deprecated) {
             continue;
         }
@@ -872,7 +869,7 @@ where
                                 }
                             }
                             sym::suggestion => {
-                                if !sess.features_untracked().deprecated_suggestion {
+                                if !features.deprecated_suggestion {
                                     sess.emit_err(session_diagnostics::DeprecatedItemSuggestion {
                                         span: mi.span,
                                         is_nightly: sess.is_nightly_build().then_some(()),
@@ -890,7 +887,7 @@ where
                                     meta.span(),
                                     AttrError::UnknownMetaItem(
                                         pprust::path_to_string(&mi.path),
-                                        if sess.features_untracked().deprecated_suggestion {
+                                        if features.deprecated_suggestion {
                                             &["since", "note", "suggestion"]
                                         } else {
                                             &["since", "note"]
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 3e90ae6907f..9302db104b6 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -69,7 +69,7 @@ pub fn expand_assert<'cx>(
     // If `generic_assert` is enabled, generates rich captured outputs
     //
     // FIXME(c410-f3r) See https://github.com/rust-lang/rust/issues/96949
-    else if let Some(features) = cx.ecfg.features && features.generic_assert {
+    else if cx.ecfg.features.generic_assert {
         context::Context::new(cx, call_site_span).build(cond_expr, panic_path())
     }
     // If `generic_assert` is not enabled, only outputs a literal "assertion failed: ..."
diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs
index 1397cee7af8..31cac51845f 100644
--- a/compiler/rustc_builtin_macros/src/cfg.rs
+++ b/compiler/rustc_builtin_macros/src/cfg.rs
@@ -24,7 +24,7 @@ pub fn expand_cfg(
                 &cfg,
                 &cx.sess.parse_sess,
                 cx.current_expansion.lint_node_id,
-                cx.ecfg.features,
+                Some(cx.ecfg.features),
             );
             MacEager::expr(cx.expr_bool(sp, matches_cfg))
         }
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 49401e9ca94..f826c6e7712 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -31,10 +31,11 @@ pub(crate) fn expand(
 
 pub(crate) fn cfg_eval(
     sess: &Session,
-    features: Option<&Features>,
+    features: &Features,
     annotatable: Annotatable,
     lint_node_id: NodeId,
 ) -> Annotatable {
+    let features = Some(features);
     CfgEval { cfg: &mut StripUnconfigured { sess, features, config_tokens: true, lint_node_id } }
         .configure_annotatable(annotatable)
         // Since the item itself has already been configured by the `InvocationCollector`,
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 7c0b36ced96..dae1bc5bfe5 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -5,6 +5,7 @@ use rustc_ast::{self as ast, attr, NodeId};
 use rustc_ast_pretty::pprust;
 use rustc_expand::base::{parse_macro_name_and_helper_attrs, ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
+use rustc_feature::Features;
 use rustc_session::Session;
 use rustc_span::hygiene::AstPass;
 use rustc_span::source_map::SourceMap;
@@ -46,13 +47,14 @@ struct CollectProcMacros<'a> {
 pub fn inject(
     krate: &mut ast::Crate,
     sess: &Session,
+    features: &Features,
     resolver: &mut dyn ResolverExpand,
     is_proc_macro_crate: bool,
     has_proc_macro_decls: bool,
     is_test_crate: bool,
     handler: &rustc_errors::Handler,
 ) {
-    let ecfg = ExpansionConfig::default("proc_macro".to_string());
+    let ecfg = ExpansionConfig::default("proc_macro".to_string(), features);
     let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
 
     let mut collect = CollectProcMacros {
diff --git a/compiler/rustc_builtin_macros/src/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
index 07e6288ed8c..3ee3112f021 100644
--- a/compiler/rustc_builtin_macros/src/standard_library_imports.rs
+++ b/compiler/rustc_builtin_macros/src/standard_library_imports.rs
@@ -1,6 +1,7 @@
 use rustc_ast::{self as ast, attr};
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::ExpansionConfig;
+use rustc_feature::Features;
 use rustc_session::Session;
 use rustc_span::edition::Edition::*;
 use rustc_span::hygiene::AstPass;
@@ -13,6 +14,7 @@ pub fn inject(
     pre_configured_attrs: &[ast::Attribute],
     resolver: &mut dyn ResolverExpand,
     sess: &Session,
+    features: &Features,
 ) -> usize {
     let orig_num_items = krate.items.len();
     let edition = sess.parse_sess.edition;
@@ -39,7 +41,7 @@ pub fn inject(
     let span = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
     let call_site = DUMMY_SP.with_call_site_ctxt(expn_id.to_expn_id());
 
-    let ecfg = ExpansionConfig::default("std_lib_injection".to_string());
+    let ecfg = ExpansionConfig::default("std_lib_injection".to_string(), features);
     let cx = ExtCtxt::new(sess, ecfg, resolver, None);
 
     // .rev() to preserve ordering above in combination with insert(0, ...)
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 507b74c2437..d8846a9f0aa 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -41,7 +41,12 @@ struct TestCtxt<'a> {
 
 /// Traverse the crate, collecting all the test functions, eliding any
 /// existing main functions, and synthesizing a main test harness
-pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn ResolverExpand) {
+pub fn inject(
+    krate: &mut ast::Crate,
+    sess: &Session,
+    features: &Features,
+    resolver: &mut dyn ResolverExpand,
+) {
     let span_diagnostic = sess.diagnostic();
     let panic_strategy = sess.panic_strategy();
     let platform_panic_strategy = sess.target.panic_strategy;
@@ -76,7 +81,7 @@ pub fn inject(krate: &mut ast::Crate, sess: &Session, resolver: &mut dyn Resolve
             resolver,
             reexport_test_harness_main,
             krate,
-            &sess.features_untracked(),
+            features,
             panic_strategy,
             test_runner,
         )
@@ -243,9 +248,7 @@ fn generate_test_harness(
     panic_strategy: PanicStrategy,
     test_runner: Option<ast::Path>,
 ) {
-    let mut econfig = ExpansionConfig::default("test".to_string());
-    econfig.features = Some(features);
-
+    let econfig = ExpansionConfig::default("test".to_string(), features);
     let ext_cx = ExtCtxt::new(sess, econfig, resolver, None);
 
     let expn_id = ext_cx.resolver.expansion_for_ast_pass(
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 12473a2bb0b..c4d2a374f0c 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -18,6 +18,7 @@ use rustc_errors::{
     Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic,
     MultiSpan, PResult,
 };
+use rustc_feature::Features;
 use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools};
 use rustc_parse::{self, parser, MACRO_ARGUMENTS};
@@ -767,6 +768,7 @@ impl SyntaxExtension {
     /// and other properties converted from attributes.
     pub fn new(
         sess: &Session,
+        features: &Features,
         kind: SyntaxExtensionKind,
         span: Span,
         helper_attrs: Vec<Symbol>,
@@ -816,7 +818,7 @@ impl SyntaxExtension {
             allow_internal_unstable: (!allow_internal_unstable.is_empty())
                 .then(|| allow_internal_unstable.into()),
             stability: stability.map(|(s, _)| s),
-            deprecation: attr::find_deprecation(&sess, attrs).map(|(d, _)| d),
+            deprecation: attr::find_deprecation(&sess, features, attrs).map(|(d, _)| d),
             helper_attrs,
             edition,
             builtin_name,
@@ -957,6 +959,7 @@ pub trait LintStoreExpand {
     fn pre_expansion_lint(
         &self,
         sess: &Session,
+        features: &Features,
         registered_tools: &RegisteredTools,
         node_id: NodeId,
         attrs: &[Attribute],
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index 165c6d47c8a..34d16bf00cd 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -796,7 +796,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             | Annotatable::FieldDef(..)
             | Annotatable::Variant(..) => panic!("unexpected annotatable"),
         };
-        if self.cx.ecfg.proc_macro_hygiene() {
+        if self.cx.ecfg.features.proc_macro_hygiene {
             return;
         }
         feature_err(
@@ -834,7 +834,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
             }
         }
 
-        if !self.cx.ecfg.proc_macro_hygiene() {
+        if !self.cx.ecfg.features.proc_macro_hygiene {
             annotatable
                 .visit_with(&mut GateProcMacroInput { parse_sess: &self.cx.sess.parse_sess });
         }
@@ -1122,6 +1122,7 @@ impl InvocationCollectorNode for P<ast::Item> {
                 if let Some(lint_store) = ecx.lint_store {
                     lint_store.pre_expansion_lint(
                         ecx.sess,
+                        ecx.ecfg.features,
                         ecx.resolver.registered_tools(),
                         ecx.current_expansion.lint_node_id,
                         &attrs,
@@ -1580,7 +1581,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     fn cfg(&self) -> StripUnconfigured<'_> {
         StripUnconfigured {
             sess: &self.cx.sess,
-            features: self.cx.ecfg.features,
+            features: Some(self.cx.ecfg.features),
             config_tokens: false,
             lint_node_id: self.cx.current_expansion.lint_node_id,
         }
@@ -1676,7 +1677,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
     // Detect use of feature-gated or invalid attributes on macro invocations
     // since they will not be detected after macro expansion.
     fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
-        let features = self.cx.ecfg.features.unwrap();
+        let features = self.cx.ecfg.features;
         let mut attrs = attrs.iter().peekable();
         let mut span: Option<Span> = None;
         while let Some(attr) = attrs.next() {
@@ -1976,7 +1977,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
 
 pub struct ExpansionConfig<'feat> {
     pub crate_name: String,
-    pub features: Option<&'feat Features>,
+    pub features: &'feat Features,
     pub recursion_limit: Limit,
     pub trace_mac: bool,
     /// If false, strip `#[test]` nodes
@@ -1987,11 +1988,11 @@ pub struct ExpansionConfig<'feat> {
     pub proc_macro_backtrace: bool,
 }
 
-impl<'feat> ExpansionConfig<'feat> {
-    pub fn default(crate_name: String) -> ExpansionConfig<'static> {
+impl ExpansionConfig<'_> {
+    pub fn default(crate_name: String, features: &Features) -> ExpansionConfig<'_> {
         ExpansionConfig {
             crate_name,
-            features: None,
+            features,
             recursion_limit: Limit::new(1024),
             trace_mac: false,
             should_test: false,
@@ -1999,8 +2000,4 @@ impl<'feat> ExpansionConfig<'feat> {
             proc_macro_backtrace: false,
         }
     }
-
-    fn proc_macro_hygiene(&self) -> bool {
-        self.features.is_some_and(|features| features.proc_macro_hygiene)
-    }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 1b935058c04..ce8b4621720 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust;
 use rustc_attr::{self as attr, TransparencyError};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{Applicability, ErrorGuaranteed};
+use rustc_feature::Features;
 use rustc_lint_defs::builtin::{
     RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
 };
@@ -375,6 +376,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
 /// Converts a macro item into a syntax extension.
 pub fn compile_declarative_macro(
     sess: &Session,
+    features: &Features,
     def: &ast::Item,
     edition: Edition,
 ) -> (SyntaxExtension, Vec<(usize, Span)>) {
@@ -382,6 +384,7 @@ pub fn compile_declarative_macro(
     let mk_syn_ext = |expander| {
         SyntaxExtension::new(
             sess,
+            features,
             SyntaxExtensionKind::LegacyBang(expander),
             def.span,
             Vec::new(),
@@ -503,7 +506,7 @@ pub fn compile_declarative_macro(
                         true,
                         &sess.parse_sess,
                         def.id,
-                        sess.features_untracked(),
+                        features,
                         edition,
                     )
                     .pop()
@@ -527,7 +530,7 @@ pub fn compile_declarative_macro(
                         false,
                         &sess.parse_sess,
                         def.id,
-                        sess.features_untracked(),
+                        features,
                         edition,
                     )
                     .pop()
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 2c7438ed9db..ae008674d01 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -15,6 +15,7 @@ rustc_attr = { path = "../rustc_attr" }
 rustc_borrowck = { path = "../rustc_borrowck" }
 rustc_builtin_macros = { path = "../rustc_builtin_macros" }
 rustc_expand = { path = "../rustc_expand" }
+rustc_feature = { path = "../rustc_feature" }
 rustc_fluent_macro = { path = "../rustc_fluent_macro" }
 rustc_fs_util = { path = "../rustc_fs_util" }
 rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index def9fdcd3c7..18a669175b9 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -11,6 +11,7 @@ use rustc_data_structures::steal::Steal;
 use rustc_data_structures::sync::{Lrc, OnceCell, WorkerLocal};
 use rustc_errors::PResult;
 use rustc_expand::base::{ExtCtxt, LintStoreExpand};
+use rustc_feature::Features;
 use rustc_fs_util::try_canonicalize;
 use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE};
 use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintStore};
@@ -98,6 +99,7 @@ pub(crate) fn create_lint_store(
 
 fn pre_expansion_lint<'a>(
     sess: &Session,
+    features: &Features,
     lint_store: &LintStore,
     registered_tools: &RegisteredTools,
     check_node: impl EarlyCheckNode<'a>,
@@ -107,6 +109,7 @@ fn pre_expansion_lint<'a>(
         || {
             rustc_lint::check_ast_node(
                 sess,
+                features,
                 true,
                 lint_store,
                 registered_tools,
@@ -125,13 +128,14 @@ impl LintStoreExpand for LintStoreExpandImpl<'_> {
     fn pre_expansion_lint(
         &self,
         sess: &Session,
+        features: &Features,
         registered_tools: &RegisteredTools,
         node_id: ast::NodeId,
         attrs: &[ast::Attribute],
         items: &[rustc_ast::ptr::P<ast::Item>],
         name: Symbol,
     ) {
-        pre_expansion_lint(sess, self.0, registered_tools, (node_id, attrs, items), name);
+        pre_expansion_lint(sess, features, self.0, registered_tools, (node_id, attrs, items), name);
     }
 }
 
@@ -147,10 +151,18 @@ fn configure_and_expand(
 ) -> ast::Crate {
     let tcx = resolver.tcx();
     let sess = tcx.sess;
+    let features = tcx.features();
     let lint_store = unerased_lint_store(tcx);
     let crate_name = tcx.crate_name(LOCAL_CRATE);
     let lint_check_node = (&krate, pre_configured_attrs);
-    pre_expansion_lint(sess, lint_store, tcx.registered_tools(()), lint_check_node, crate_name);
+    pre_expansion_lint(
+        sess,
+        features,
+        lint_store,
+        tcx.registered_tools(()),
+        lint_check_node,
+        crate_name,
+    );
     rustc_builtin_macros::register_builtin_macros(resolver);
 
     let num_standard_library_imports = sess.time("crate_injection", || {
@@ -159,6 +171,7 @@ fn configure_and_expand(
             pre_configured_attrs,
             resolver,
             sess,
+            features,
         )
     });
 
@@ -198,16 +211,15 @@ fn configure_and_expand(
         }
 
         // Create the config for macro expansion
-        let features = sess.features_untracked();
         let recursion_limit = get_recursion_limit(pre_configured_attrs, sess);
         let cfg = rustc_expand::expand::ExpansionConfig {
-            features: Some(features),
+            crate_name: crate_name.to_string(),
+            features,
             recursion_limit,
             trace_mac: sess.opts.unstable_opts.trace_macros,
             should_test: sess.is_test_crate(),
             span_debug: sess.opts.unstable_opts.span_debug,
             proc_macro_backtrace: sess.opts.unstable_opts.proc_macro_backtrace,
-            ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string())
         };
 
         let lint_store = LintStoreExpandImpl(lint_store);
@@ -241,11 +253,16 @@ fn configure_and_expand(
     });
 
     sess.time("maybe_building_test_harness", || {
-        rustc_builtin_macros::test_harness::inject(&mut krate, sess, resolver)
+        rustc_builtin_macros::test_harness::inject(&mut krate, sess, features, resolver)
     });
 
     let has_proc_macro_decls = sess.time("AST_validation", || {
-        rustc_ast_passes::ast_validation::check_crate(sess, &krate, resolver.lint_buffer())
+        rustc_ast_passes::ast_validation::check_crate(
+            sess,
+            features,
+            &krate,
+            resolver.lint_buffer(),
+        )
     });
 
     let crate_types = tcx.crate_types();
@@ -270,6 +287,7 @@ fn configure_and_expand(
         rustc_builtin_macros::proc_macro_harness::inject(
             &mut krate,
             sess,
+            features,
             resolver,
             is_proc_macro_crate,
             has_proc_macro_decls,
@@ -300,7 +318,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
 
     // Needs to go *after* expansion to be able to check the results of macro expansion.
     sess.time("complete_gated_feature_checking", || {
-        rustc_ast_passes::feature_gate::check_crate(&krate, sess);
+        rustc_ast_passes::feature_gate::check_crate(&krate, sess, tcx.features());
     });
 
     // Add all buffered lints from the `ParseSess` to the `Session`.
@@ -329,6 +347,7 @@ fn early_lint_checks(tcx: TyCtxt<'_>, (): ()) {
     let lint_store = unerased_lint_store(tcx);
     rustc_lint::check_ast_node(
         sess,
+        tcx.features(),
         false,
         lint_store,
         tcx.registered_tools(()),
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 7687e83da76..5d38cf770a2 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -234,9 +234,6 @@ impl<'tcx> Queries<'tcx> {
             debug_assert_eq!(_id, CRATE_DEF_ID);
             let untracked = Untracked { cstore, source_span, definitions };
 
-            // FIXME: Move features from session to tcx and make them immutable.
-            sess.init_features(rustc_expand::config::features(sess, &pre_configured_attrs));
-
             let qcx = passes::create_global_ctxt(
                 self.compiler,
                 crate_types,
@@ -254,11 +251,13 @@ impl<'tcx> Queries<'tcx> {
                 feed.crate_name(crate_name);
 
                 let feed = tcx.feed_unit_query();
+                feed.features_query(
+                    tcx.arena.alloc(rustc_expand::config::features(sess, &pre_configured_attrs)),
+                );
                 feed.crate_for_resolver(tcx.arena.alloc(Steal::new((krate, pre_configured_attrs))));
                 feed.metadata_loader(
                     tcx.arena.alloc(Steal::new(self.codegen_backend().metadata_loader())),
                 );
-                feed.features_query(tcx.sess.features_untracked());
             });
             Ok(qcx)
         })
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 2c9d212a6a6..7a430c1df85 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -2237,7 +2237,7 @@ declare_lint_pass!(
 
 impl EarlyLintPass for IncompleteInternalFeatures {
     fn check_crate(&mut self, cx: &EarlyContext<'_>, _: &ast::Crate) {
-        let features = cx.sess().features_untracked();
+        let features = cx.builder.features();
         features
             .declared_lang_features
             .iter()
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index f7e56b30553..f73797415bc 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -27,6 +27,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync;
 use rustc_errors::{add_elided_lifetime_in_path_suggestion, DiagnosticBuilder, DiagnosticMessage};
 use rustc_errors::{Applicability, DecorateLint, MultiSpan, SuggestionStyle};
+use rustc_feature::Features;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::{CrateNum, DefId};
@@ -1071,6 +1072,7 @@ pub trait LintContext: Sized {
 impl<'a> EarlyContext<'a> {
     pub(crate) fn new(
         sess: &'a Session,
+        features: &'a Features,
         warn_about_weird_lints: bool,
         lint_store: &'a LintStore,
         registered_tools: &'a RegisteredTools,
@@ -1079,6 +1081,7 @@ impl<'a> EarlyContext<'a> {
         EarlyContext {
             builder: LintLevelsBuilder::new(
                 sess,
+                features,
                 warn_about_weird_lints,
                 lint_store,
                 registered_tools,
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 9f1f5a26ee5..211ea8f4347 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -20,6 +20,7 @@ use rustc_ast::ptr::P;
 use rustc_ast::visit::{self as ast_visit, Visitor};
 use rustc_ast::{self as ast, walk_list, HasAttrs};
 use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_feature::Features;
 use rustc_middle::ty::RegisteredTools;
 use rustc_session::lint::{BufferedEarlyLint, LintBuffer, LintPass};
 use rustc_session::Session;
@@ -381,6 +382,7 @@ impl<'a> EarlyCheckNode<'a> for (ast::NodeId, &'a [ast::Attribute], &'a [P<ast::
 
 pub fn check_ast_node<'a>(
     sess: &Session,
+    features: &Features,
     pre_expansion: bool,
     lint_store: &LintStore,
     registered_tools: &RegisteredTools,
@@ -390,6 +392,7 @@ pub fn check_ast_node<'a>(
 ) {
     let context = EarlyContext::new(
         sess,
+        features,
         !pre_expansion,
         lint_store,
         registered_tools,
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index 18b178d8882..1f4e5fa4d3b 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -12,6 +12,7 @@ use rustc_ast as ast;
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan};
+use rustc_feature::Features;
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::HirId;
@@ -119,6 +120,7 @@ fn lint_expectations(tcx: TyCtxt<'_>, (): ()) -> Vec<(LintExpectationId, LintExp
 
     let mut builder = LintLevelsBuilder {
         sess: tcx.sess,
+        features: tcx.features(),
         provider: QueryMapExpectationsWrapper {
             tcx,
             cur: hir::CRATE_HIR_ID,
@@ -148,6 +150,7 @@ fn shallow_lint_levels_on(tcx: TyCtxt<'_>, owner: hir::OwnerId) -> ShallowLintLe
 
     let mut levels = LintLevelsBuilder {
         sess: tcx.sess,
+        features: tcx.features(),
         provider: LintLevelQueryMap {
             tcx,
             cur: owner.into(),
@@ -435,6 +438,7 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'
 
 pub struct LintLevelsBuilder<'s, P> {
     sess: &'s Session,
+    features: &'s Features,
     provider: P,
     warn_about_weird_lints: bool,
     store: &'s LintStore,
@@ -448,12 +452,14 @@ pub(crate) struct BuilderPush {
 impl<'s> LintLevelsBuilder<'s, TopDown> {
     pub(crate) fn new(
         sess: &'s Session,
+        features: &'s Features,
         warn_about_weird_lints: bool,
         store: &'s LintStore,
         registered_tools: &'s RegisteredTools,
     ) -> Self {
         let mut builder = LintLevelsBuilder {
             sess,
+            features,
             provider: TopDown { sets: LintLevelSets::new(), cur: COMMAND_LINE },
             warn_about_weird_lints,
             store,
@@ -526,6 +532,10 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
         self.sess
     }
 
+    pub(crate) fn features(&self) -> &Features {
+        self.features
+    }
+
     pub(crate) fn lint_store(&self) -> &LintStore {
         self.store
     }
@@ -716,7 +726,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
                     ast::MetaItemKind::NameValue(ref name_value) => {
                         if item.path == sym::reason {
                             if let ast::LitKind::Str(rationale, _) = name_value.kind {
-                                if !self.sess.features_untracked().lint_reasons {
+                                if !self.features.lint_reasons {
                                     feature_err(
                                         &self.sess.parse_sess,
                                         sym::lint_reasons,
@@ -992,7 +1002,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> {
     #[track_caller]
     fn check_gated_lint(&self, lint_id: LintId, span: Span) -> bool {
         if let Some(feature) = lint_id.lint.feature_gate {
-            if !self.sess.features_untracked().enabled(feature) {
+            if !self.features.enabled(feature) {
                 let lint = builtin::UNKNOWN_LINTS;
                 let (level, src) = self.lint_level(builtin::UNKNOWN_LINTS);
                 struct_lint_level(
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 9e67bb655d4..e8f66c36a86 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -842,7 +842,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             .decode((self, sess))
     }
 
-    fn load_proc_macro(self, id: DefIndex, sess: &Session) -> SyntaxExtension {
+    fn load_proc_macro(self, id: DefIndex, tcx: TyCtxt<'tcx>) -> SyntaxExtension {
         let (name, kind, helper_attrs) = match *self.raw_proc_macro(id) {
             ProcMacro::CustomDerive { trait_name, attributes, client } => {
                 let helper_attrs =
@@ -861,9 +861,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
             }
         };
 
+        let sess = tcx.sess;
         let attrs: Vec<_> = self.get_item_attrs(id, sess).collect();
         SyntaxExtension::new(
             sess,
+            tcx.features(),
             kind,
             self.get_span(id, sess),
             helper_attrs,
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 7dbfe0e0cb0..aeda8af6d2c 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -6,6 +6,7 @@ use crate::rmeta::AttrFlags;
 
 use rustc_ast as ast;
 use rustc_attr::Deprecation;
+use rustc_data_structures::sync::Lrc;
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
@@ -23,7 +24,6 @@ use rustc_span::hygiene::{ExpnHash, ExpnId};
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::Span;
 
-use rustc_data_structures::sync::Lrc;
 use std::any::Any;
 
 use super::{Decodable, DecodeContext, DecodeIterator};
@@ -522,12 +522,13 @@ impl CStore {
         self.get_crate_data(def.krate).get_ctor(def.index)
     }
 
-    pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
+    pub fn load_macro_untracked(&self, id: DefId, tcx: TyCtxt<'_>) -> LoadedMacro {
+        let sess = tcx.sess;
         let _prof_timer = sess.prof.generic_activity("metadata_load_macro");
 
         let data = self.get_crate_data(id.krate);
         if data.root.is_proc_macro_crate() {
-            return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, sess));
+            return LoadedMacro::ProcMacro(data.load_proc_macro(id.index, tcx));
         }
 
         let span = data.get_span(id.index, sess);
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 5a320865c95..b056ae420ab 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -131,6 +131,7 @@ macro_rules! arena_types {
             [] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>),
             [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem,
             [] mod_child: rustc_middle::metadata::ModChild,
+            [] features: rustc_feature::Features,
         ]);
     )
 }
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 3950ac9dd31..bd2336410b9 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -115,7 +115,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
         let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id));
         debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs);
 
-        let depr = attr::find_deprecation(&self.tcx.sess, attrs);
+        let depr = attr::find_deprecation(self.tcx.sess, self.tcx.features(), attrs);
         let mut is_deprecated = false;
         if let Some((depr, span)) = &depr {
             is_deprecated = true;
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index a655667d01d..127bec22c17 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -171,7 +171,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
             return macro_data.clone();
         }
 
-        let load_macro_untracked = self.cstore().load_macro_untracked(def_id, &self.tcx.sess);
+        let load_macro_untracked = self.cstore().load_macro_untracked(def_id, self.tcx);
         let (ext, macro_rules) = match load_macro_untracked {
             LoadedMacro::MacroDef(item, edition) => (
                 Lrc::new(self.compile_macro(&item, edition).0),
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index e403386e60c..76e54e60d14 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -1282,7 +1282,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
 
         let registered_tools = tcx.registered_tools(());
 
-        let features = tcx.sess.features_untracked();
+        let features = tcx.features();
 
         let mut resolver = Resolver {
             tcx,
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 614a29e7578..6a5b675b4bb 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -920,7 +920,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
         item: &ast::Item,
         edition: Edition,
     ) -> (SyntaxExtension, Vec<(usize, Span)>) {
-        let (mut result, mut rule_spans) = compile_declarative_macro(self.tcx.sess, item, edition);
+        let (mut result, mut rule_spans) =
+            compile_declarative_macro(self.tcx.sess, self.tcx.features(), item, edition);
 
         if let Some(builtin_name) = result.builtin_name {
             // The macro was marked with `#[rustc_builtin_macro]`.
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 5d7572f65a5..086ce4e6964 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -17,7 +17,7 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
 use rustc_data_structures::jobserver::{self, Client};
 use rustc_data_structures::profiling::{duration_to_secs_str, SelfProfiler, SelfProfilerRef};
 use rustc_data_structures::sync::{
-    self, AtomicU64, AtomicUsize, Lock, Lrc, OnceCell, OneThread, Ordering, Ordering::SeqCst,
+    self, AtomicU64, AtomicUsize, Lock, Lrc, OneThread, Ordering, Ordering::SeqCst,
 };
 use rustc_errors::annotate_snippet_emitter_writer::AnnotateSnippetEmitterWriter;
 use rustc_errors::emitter::{Emitter, EmitterWriter, HumanReadableErrorType};
@@ -152,8 +152,6 @@ pub struct Session {
     /// Input, input file path and output file path to this compilation process.
     pub io: CompilerIO,
 
-    features: OnceCell<rustc_feature::Features>,
-
     incr_comp_session: OneThread<RefCell<IncrCompSession>>,
     /// Used for incremental compilation tests. Will only be populated if
     /// `-Zquery-dep-graph` is specified.
@@ -705,21 +703,6 @@ impl Session {
         self.opts.cg.instrument_coverage() == InstrumentCoverage::ExceptUnusedFunctions
     }
 
-    /// Gets the features enabled for the current compilation session.
-    /// DO NOT USE THIS METHOD if there is a TyCtxt available, as it circumvents
-    /// dependency tracking. Use tcx.features() instead.
-    #[inline]
-    pub fn features_untracked(&self) -> &rustc_feature::Features {
-        self.features.get().unwrap()
-    }
-
-    pub fn init_features(&self, features: rustc_feature::Features) {
-        match self.features.set(features) {
-            Ok(()) => {}
-            Err(_) => panic!("`features` was initialized twice"),
-        }
-    }
-
     pub fn is_sanitizer_cfi_enabled(&self) -> bool {
         self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
     }
@@ -1464,7 +1447,6 @@ pub fn build_session(
         parse_sess,
         sysroot,
         io,
-        features: OnceCell::new(),
         incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)),
         cgu_reuse_tracker,
         prof,
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 384010034e6..389bac0f09d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -200,7 +200,7 @@ pub(crate) fn record_extern_fqn(cx: &mut DocContext<'_>, did: DefId, kind: ItemT
     let fqn = if let ItemType::Macro = kind {
         // Check to see if it is a macro 2.0 or built-in macro
         if matches!(
-            CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.sess()),
+            CStore::from_tcx(cx.tcx).load_macro_untracked(did, cx.tcx),
             LoadedMacro::MacroDef(def, _)
                 if matches!(&def.kind, ast::ItemKind::MacroDef(ast_def)
                     if !ast_def.macro_rules)
@@ -680,7 +680,7 @@ fn build_macro(
     import_def_id: Option<DefId>,
     macro_kind: MacroKind,
 ) -> clean::ItemKind {
-    match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.sess()) {
+    match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
         LoadedMacro::MacroDef(item_def, _) => match macro_kind {
             MacroKind::Bang => {
                 if let ast::ItemKind::MacroDef(ref def) = item_def.kind {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index eb5d3c88570..58022046294 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -604,7 +604,7 @@ fn generate_macro_def_id_path(
     }
     // Check to see if it is a macro 2.0 or built-in macro.
     // More information in <https://rust-lang.github.io/rfcs/1584-macros.html>.
-    let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx.sess) {
+    let is_macro_2 = match cstore.load_macro_untracked(def_id, tcx) {
         LoadedMacro::MacroDef(def, _) => {
             // If `ast_def.macro_rules` is `true`, then it's not a macro 2.0.
             matches!(&def.kind, ast::ItemKind::MacroDef(ast_def) if !ast_def.macro_rules)