rustc_expand/
config.rs

1//! Conditional compilation stripping.
2
3use std::iter;
4
5use rustc_ast::token::{Delimiter, Token, TokenKind};
6use rustc_ast::tokenstream::{
7    AttrTokenStream, AttrTokenTree, LazyAttrTokenStream, Spacing, TokenTree,
8};
9use rustc_ast::{
10    self as ast, AttrItemKind, AttrKind, AttrStyle, Attribute, EarlyParsedAttribute, HasAttrs,
11    HasTokens, MetaItem, MetaItemInner, NodeId, NormalAttr,
12};
13use rustc_attr_parsing as attr;
14use rustc_attr_parsing::{
15    AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg,
16};
17use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
18use rustc_feature::{
19    ACCEPTED_LANG_FEATURES, EnabledLangFeature, EnabledLibFeature, Features, REMOVED_LANG_FEATURES,
20    UNSTABLE_LANG_FEATURES,
21};
22use rustc_hir::Target;
23use rustc_session::Session;
24use rustc_session::parse::feature_err;
25use rustc_span::{STDLIB_STABLE_CRATES, Span, Symbol, sym};
26use thin_vec::ThinVec;
27use tracing::instrument;
28
29use crate::errors::{
30    CrateNameInCfgAttr, CrateTypeInCfgAttr, FeatureNotAllowed, FeatureRemoved,
31    FeatureRemovedReason, InvalidCfg, MalformedFeatureAttribute, MalformedFeatureAttributeHelp,
32    RemoveExprNotSupported,
33};
34
35/// A folder that strips out items that do not belong in the current configuration.
36pub struct StripUnconfigured<'a> {
37    pub sess: &'a Session,
38    pub features: Option<&'a Features>,
39    /// If `true`, perform cfg-stripping on attached tokens.
40    /// This is only used for the input to derive macros,
41    /// which needs eager expansion of `cfg` and `cfg_attr`
42    pub config_tokens: bool,
43    pub lint_node_id: NodeId,
44}
45
46pub fn features(sess: &Session, krate_attrs: &[Attribute], crate_name: Symbol) -> Features {
47    fn feature_list(attr: &Attribute) -> ThinVec<ast::MetaItemInner> {
48        if attr.has_name(sym::feature)
49            && let Some(list) = attr.meta_item_list()
50        {
51            list
52        } else {
53            ThinVec::new()
54        }
55    }
56
57    let mut features = Features::default();
58
59    // Process all features enabled in the code.
60    for attr in krate_attrs {
61        for mi in feature_list(attr) {
62            let name = match mi.ident() {
63                Some(ident) if mi.is_word() => ident.name,
64                Some(ident) => {
65                    sess.dcx().emit_err(MalformedFeatureAttribute {
66                        span: mi.span(),
67                        help: MalformedFeatureAttributeHelp::Suggestion {
68                            span: mi.span(),
69                            suggestion: ident.name,
70                        },
71                    });
72                    continue;
73                }
74                None => {
75                    sess.dcx().emit_err(MalformedFeatureAttribute {
76                        span: mi.span(),
77                        help: MalformedFeatureAttributeHelp::Label { span: mi.span() },
78                    });
79                    continue;
80                }
81            };
82
83            // If the enabled feature has been removed, issue an error.
84            if let Some(f) = REMOVED_LANG_FEATURES.iter().find(|f| name == f.feature.name) {
85                let pull_note = if let Some(pull) = f.pull {
86                    ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("; see <https://github.com/rust-lang/rust/pull/{0}> for more information",
                pull))
    })format!(
87                        "; see <https://github.com/rust-lang/rust/pull/{}> for more information",
88                        pull
89                    )
90                } else {
91                    "".to_owned()
92                };
93                sess.dcx().emit_err(FeatureRemoved {
94                    span: mi.span(),
95                    reason: f.reason.map(|reason| FeatureRemovedReason { reason }),
96                    removed_rustc_version: f.feature.since,
97                    pull_note,
98                });
99                continue;
100            }
101
102            // If the enabled feature is stable, record it.
103            if let Some(f) = ACCEPTED_LANG_FEATURES.iter().find(|f| name == f.name) {
104                features.set_enabled_lang_feature(EnabledLangFeature {
105                    gate_name: name,
106                    attr_sp: mi.span(),
107                    stable_since: Some(Symbol::intern(f.since)),
108                });
109                continue;
110            }
111
112            // If `-Z allow-features` is used and the enabled feature is
113            // unstable and not also listed as one of the allowed features,
114            // issue an error.
115            if let Some(allowed) = sess.opts.unstable_opts.allow_features.as_ref() {
116                if allowed.iter().all(|f| name.as_str() != f) {
117                    sess.dcx().emit_err(FeatureNotAllowed { span: mi.span(), name });
118                    continue;
119                }
120            }
121
122            // If the enabled feature is unstable, record it.
123            if UNSTABLE_LANG_FEATURES.iter().find(|f| name == f.name).is_some() {
124                // When the ICE comes a standard library crate, there's a chance that the person
125                // hitting the ICE may be using -Zbuild-std or similar with an untested target.
126                // The bug is probably in the standard library and not the compiler in that case,
127                // but that doesn't really matter - we want a bug report.
128                if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) {
129                    sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
130                }
131
132                features.set_enabled_lang_feature(EnabledLangFeature {
133                    gate_name: name,
134                    attr_sp: mi.span(),
135                    stable_since: None,
136                });
137                continue;
138            }
139
140            // Otherwise, the feature is unknown. Enable it as a lib feature.
141            // It will be checked later whether the feature really exists.
142            features
143                .set_enabled_lib_feature(EnabledLibFeature { gate_name: name, attr_sp: mi.span() });
144
145            // Similar to above, detect internal lib features to suppress
146            // the ICE message that asks for a report.
147            if features.internal(name) && !STDLIB_STABLE_CRATES.contains(&crate_name) {
148                sess.using_internal_features.store(true, std::sync::atomic::Ordering::Relaxed);
149            }
150        }
151    }
152
153    features
154}
155
156pub fn pre_configure_attrs(sess: &Session, attrs: &[Attribute]) -> ast::AttrVec {
157    let strip_unconfigured = StripUnconfigured {
158        sess,
159        features: None,
160        config_tokens: false,
161        lint_node_id: ast::CRATE_NODE_ID,
162    };
163    attrs
164        .iter()
165        .flat_map(|attr| strip_unconfigured.process_cfg_attr(attr))
166        .take_while(|attr| {
167            !is_cfg(attr) || strip_unconfigured.cfg_true(attr, ShouldEmit::Nothing).as_bool()
168        })
169        .collect()
170}
171
172pub(crate) fn attr_into_trace(mut attr: Attribute, trace_name: Symbol) -> Attribute {
173    match &mut attr.kind {
174        AttrKind::Normal(normal) => {
175            let NormalAttr { item, tokens } = &mut **normal;
176            item.path.segments[0].ident.name = trace_name;
177            // This makes the trace attributes unobservable to token-based proc macros.
178            *tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::default()));
179        }
180        AttrKind::DocComment(..) => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
181    }
182    attr
183}
184
185#[macro_export]
186macro_rules! configure {
187    ($this:ident, $node:ident) => {
188        match $this.configure($node) {
189            Some(node) => node,
190            None => return Default::default(),
191        }
192    };
193}
194
195impl<'a> StripUnconfigured<'a> {
196    pub fn configure<T: HasAttrs + HasTokens>(&self, mut node: T) -> Option<T> {
197        self.process_cfg_attrs(&mut node);
198        self.in_cfg(node.attrs()).then(|| {
199            self.try_configure_tokens(&mut node);
200            node
201        })
202    }
203
204    fn try_configure_tokens<T: HasTokens>(&self, node: &mut T) {
205        if self.config_tokens {
206            if let Some(Some(tokens)) = node.tokens_mut() {
207                let attr_stream = tokens.to_attr_token_stream();
208                *tokens = LazyAttrTokenStream::new_direct(self.configure_tokens(&attr_stream));
209            }
210        }
211    }
212
213    /// Performs cfg-expansion on `stream`, producing a new `AttrTokenStream`.
214    /// This is only used during the invocation of `derive` proc-macros,
215    /// which require that we cfg-expand their entire input.
216    /// Normal cfg-expansion operates on parsed AST nodes via the `configure` method
217    fn configure_tokens(&self, stream: &AttrTokenStream) -> AttrTokenStream {
218        fn can_skip(stream: &AttrTokenStream) -> bool {
219            stream.0.iter().all(|tree| match tree {
220                AttrTokenTree::AttrsTarget(_) => false,
221                AttrTokenTree::Token(..) => true,
222                AttrTokenTree::Delimited(.., inner) => can_skip(inner),
223            })
224        }
225
226        if can_skip(stream) {
227            return stream.clone();
228        }
229
230        let trees: Vec<_> = stream
231            .0
232            .iter()
233            .filter_map(|tree| match tree.clone() {
234                AttrTokenTree::AttrsTarget(mut target) => {
235                    // Expand any `cfg_attr` attributes.
236                    target.attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
237
238                    if self.in_cfg(&target.attrs) {
239                        target.tokens = LazyAttrTokenStream::new_direct(
240                            self.configure_tokens(&target.tokens.to_attr_token_stream()),
241                        );
242                        Some(AttrTokenTree::AttrsTarget(target))
243                    } else {
244                        // Remove the target if there's a `cfg` attribute and
245                        // the condition isn't satisfied.
246                        None
247                    }
248                }
249                AttrTokenTree::Delimited(sp, spacing, delim, mut inner) => {
250                    inner = self.configure_tokens(&inner);
251                    Some(AttrTokenTree::Delimited(sp, spacing, delim, inner))
252                }
253                AttrTokenTree::Token(Token { kind, .. }, _) if kind.is_delim() => {
254                    {
    ::core::panicking::panic_fmt(format_args!("Should be `AttrTokenTree::Delimited`, not delim tokens: {0:?}",
            tree));
};panic!("Should be `AttrTokenTree::Delimited`, not delim tokens: {:?}", tree);
255                }
256                AttrTokenTree::Token(token, spacing) => Some(AttrTokenTree::Token(token, spacing)),
257            })
258            .collect();
259        AttrTokenStream::new(trees)
260    }
261
262    /// Parse and expand all `cfg_attr` attributes into a list of attributes
263    /// that are within each `cfg_attr` that has a true configuration predicate.
264    ///
265    /// Gives compiler warnings if any `cfg_attr` does not contain any
266    /// attributes and is in the original source code. Gives compiler errors if
267    /// the syntax of any `cfg_attr` is incorrect.
268    fn process_cfg_attrs<T: HasAttrs>(&self, node: &mut T) {
269        node.visit_attrs(|attrs| {
270            attrs.flat_map_in_place(|attr| self.process_cfg_attr(&attr));
271        });
272    }
273
274    fn process_cfg_attr(&self, attr: &Attribute) -> Vec<Attribute> {
275        if attr.has_name(sym::cfg_attr) {
276            self.expand_cfg_attr(attr, true)
277        } else {
278            <[_]>::into_vec(::alloc::boxed::box_new([attr.clone()]))vec![attr.clone()]
279        }
280    }
281
282    /// Parse and expand a single `cfg_attr` attribute into a list of attributes
283    /// when the configuration predicate is true, or otherwise expand into an
284    /// empty list of attributes.
285    ///
286    /// Gives a compiler warning when the `cfg_attr` contains no attributes and
287    /// is in the original source file. Gives a compiler error if the syntax of
288    /// the attribute is incorrect.
289    pub(crate) fn expand_cfg_attr(&self, cfg_attr: &Attribute, recursive: bool) -> Vec<Attribute> {
290        // A trace attribute left in AST in place of the original `cfg_attr` attribute.
291        // It can later be used by lints or other diagnostics.
292        let mut trace_attr = cfg_attr.clone();
293        trace_attr.replace_args(AttrItemKind::Parsed(EarlyParsedAttribute::CfgAttrTrace));
294        let trace_attr = attr_into_trace(trace_attr, sym::cfg_attr_trace);
295
296        let Some((cfg_predicate, expanded_attrs)) =
297            rustc_attr_parsing::parse_cfg_attr(cfg_attr, &self.sess, self.features)
298        else {
299            return <[_]>::into_vec(::alloc::boxed::box_new([trace_attr]))vec![trace_attr];
300        };
301
302        // Lint on zero attributes in source.
303        if expanded_attrs.is_empty() {
304            self.sess.psess.buffer_lint(
305                rustc_lint_defs::builtin::UNUSED_ATTRIBUTES,
306                cfg_attr.span,
307                ast::CRATE_NODE_ID,
308                crate::errors::CfgAttrNoAttributes,
309            );
310        }
311
312        if !attr::eval_config_entry(self.sess, &cfg_predicate).as_bool() {
313            return <[_]>::into_vec(::alloc::boxed::box_new([trace_attr]))vec![trace_attr];
314        }
315
316        if recursive {
317            // We call `process_cfg_attr` recursively in case there's a
318            // `cfg_attr` inside of another `cfg_attr`. E.g.
319            //  `#[cfg_attr(false, cfg_attr(true, some_attr))]`.
320            let expanded_attrs = expanded_attrs
321                .into_iter()
322                .flat_map(|item| self.process_cfg_attr(&self.expand_cfg_attr_item(cfg_attr, item)));
323            iter::once(trace_attr).chain(expanded_attrs).collect()
324        } else {
325            let expanded_attrs =
326                expanded_attrs.into_iter().map(|item| self.expand_cfg_attr_item(cfg_attr, item));
327            iter::once(trace_attr).chain(expanded_attrs).collect()
328        }
329    }
330
331    fn expand_cfg_attr_item(
332        &self,
333        cfg_attr: &Attribute,
334        (item, item_span): (ast::AttrItem, Span),
335    ) -> Attribute {
336        // Convert `#[cfg_attr(pred, attr)]` to `#[attr]`.
337
338        // Use the `#` from `#[cfg_attr(pred, attr)]` in the result `#[attr]`.
339        let mut orig_trees = cfg_attr.token_trees().into_iter();
340        let Some(TokenTree::Token(pound_token @ Token { kind: TokenKind::Pound, .. }, _)) =
341            orig_trees.next()
342        else {
343            {
    ::core::panicking::panic_fmt(format_args!("Bad tokens for attribute {0:?}",
            cfg_attr));
};panic!("Bad tokens for attribute {cfg_attr:?}");
344        };
345
346        // For inner attributes, we do the same thing for the `!` in `#![attr]`.
347        let mut trees = if cfg_attr.style == AttrStyle::Inner {
348            let Some(TokenTree::Token(bang_token @ Token { kind: TokenKind::Bang, .. }, _)) =
349                orig_trees.next()
350            else {
351                {
    ::core::panicking::panic_fmt(format_args!("Bad tokens for attribute {0:?}",
            cfg_attr));
};panic!("Bad tokens for attribute {cfg_attr:?}");
352            };
353            <[_]>::into_vec(::alloc::boxed::box_new([AttrTokenTree::Token(pound_token,
                    Spacing::Joint),
                AttrTokenTree::Token(bang_token, Spacing::JointHidden)]))vec![
354                AttrTokenTree::Token(pound_token, Spacing::Joint),
355                AttrTokenTree::Token(bang_token, Spacing::JointHidden),
356            ]
357        } else {
358            <[_]>::into_vec(::alloc::boxed::box_new([AttrTokenTree::Token(pound_token,
                    Spacing::JointHidden)]))vec![AttrTokenTree::Token(pound_token, Spacing::JointHidden)]
359        };
360
361        // And the same thing for the `[`/`]` delimiters in `#[attr]`.
362        let Some(TokenTree::Delimited(delim_span, delim_spacing, Delimiter::Bracket, _)) =
363            orig_trees.next()
364        else {
365            {
    ::core::panicking::panic_fmt(format_args!("Bad tokens for attribute {0:?}",
            cfg_attr));
};panic!("Bad tokens for attribute {cfg_attr:?}");
366        };
367        trees.push(AttrTokenTree::Delimited(
368            delim_span,
369            delim_spacing,
370            Delimiter::Bracket,
371            item.tokens
372                .as_ref()
373                .unwrap_or_else(|| {
    ::core::panicking::panic_fmt(format_args!("Missing tokens for {0:?}",
            item));
}panic!("Missing tokens for {item:?}"))
374                .to_attr_token_stream(),
375        ));
376
377        let tokens = Some(LazyAttrTokenStream::new_direct(AttrTokenStream::new(trees)));
378        let attr = ast::attr::mk_attr_from_item(
379            &self.sess.psess.attr_id_generator,
380            item,
381            tokens,
382            cfg_attr.style,
383            item_span,
384        );
385        if attr.has_name(sym::crate_type) {
386            self.sess.dcx().emit_err(CrateTypeInCfgAttr { span: attr.span });
387        }
388        if attr.has_name(sym::crate_name) {
389            self.sess.dcx().emit_err(CrateNameInCfgAttr { span: attr.span });
390        }
391        attr
392    }
393
394    /// Determines if a node with the given attributes should be included in this configuration.
395    fn in_cfg(&self, attrs: &[Attribute]) -> bool {
396        attrs
397            .iter()
398            .all(|attr| !is_cfg(attr) || self.cfg_true(attr, ShouldEmit::ErrorsAndLints).as_bool())
399    }
400
401    pub(crate) fn cfg_true(&self, attr: &Attribute, emit_errors: ShouldEmit) -> EvalConfigResult {
402        let Some(cfg) = AttributeParser::parse_single(
403            self.sess,
404            attr,
405            attr.span,
406            self.lint_node_id,
407            // Doesn't matter what the target actually is here.
408            Target::Crate,
409            self.features,
410            emit_errors,
411            parse_cfg,
412            &CFG_TEMPLATE,
413        ) else {
414            // Cfg attribute was not parsable, give up
415            return EvalConfigResult::True;
416        };
417
418        eval_config_entry(self.sess, &cfg)
419    }
420
421    /// If attributes are not allowed on expressions, emit an error for `attr`
422    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("maybe_emit_expr_attr_err",
                                    "rustc_expand::config", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_expand/src/config.rs"),
                                    ::tracing_core::__macro_support::Option::Some(422u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_expand::config"),
                                    ::tracing_core::field::FieldSet::new(&["attr"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&attr)
                                                            as &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if self.features.is_some_and(|features|
                            !features.stmt_expr_attributes()) &&
                    !attr.span.allows_unstable(sym::stmt_expr_attributes) {
                let mut err =
                    feature_err(&self.sess, sym::stmt_expr_attributes,
                        attr.span,
                        crate::fluent_generated::expand_attributes_on_expressions_experimental);
                if attr.is_doc_comment() {
                    err.help(if attr.style == AttrStyle::Outer {
                            crate::fluent_generated::expand_help_outer_doc
                        } else { crate::fluent_generated::expand_help_inner_doc });
                }
                err.emit();
            }
        }
    }
}#[instrument(level = "trace", skip(self))]
423    pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
424        if self.features.is_some_and(|features| !features.stmt_expr_attributes())
425            && !attr.span.allows_unstable(sym::stmt_expr_attributes)
426        {
427            let mut err = feature_err(
428                &self.sess,
429                sym::stmt_expr_attributes,
430                attr.span,
431                crate::fluent_generated::expand_attributes_on_expressions_experimental,
432            );
433
434            if attr.is_doc_comment() {
435                err.help(if attr.style == AttrStyle::Outer {
436                    crate::fluent_generated::expand_help_outer_doc
437                } else {
438                    crate::fluent_generated::expand_help_inner_doc
439                });
440            }
441
442            err.emit();
443        }
444    }
445
446    #[allow(clippy :: suspicious_else_formatting)]
{
    let __tracing_attr_span;
    let __tracing_attr_guard;
    if ::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::TRACE <=
                    ::tracing::level_filters::LevelFilter::current() ||
            { false } {
        __tracing_attr_span =
            {
                use ::tracing::__macro_support::Callsite as _;
                static __CALLSITE: ::tracing::callsite::DefaultCallsite =
                    {
                        static META: ::tracing::Metadata<'static> =
                            {
                                ::tracing_core::metadata::Metadata::new("configure_expr",
                                    "rustc_expand::config", ::tracing::Level::TRACE,
                                    ::tracing_core::__macro_support::Option::Some("compiler/rustc_expand/src/config.rs"),
                                    ::tracing_core::__macro_support::Option::Some(446u32),
                                    ::tracing_core::__macro_support::Option::Some("rustc_expand::config"),
                                    ::tracing_core::field::FieldSet::new(&["expr",
                                                    "method_receiver"],
                                        ::tracing_core::callsite::Identifier(&__CALLSITE)),
                                    ::tracing::metadata::Kind::SPAN)
                            };
                        ::tracing::callsite::DefaultCallsite::new(&META)
                    };
                let mut interest = ::tracing::subscriber::Interest::never();
                if ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::STATIC_MAX_LEVEL &&
                                ::tracing::Level::TRACE <=
                                    ::tracing::level_filters::LevelFilter::current() &&
                            { interest = __CALLSITE.interest(); !interest.is_never() }
                        &&
                        ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                            interest) {
                    let meta = __CALLSITE.metadata();
                    ::tracing::Span::new(meta,
                        &{
                                #[allow(unused_imports)]
                                use ::tracing::field::{debug, display, Value};
                                let mut iter = meta.fields().iter();
                                meta.fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&::tracing::field::debug(&expr)
                                                            as &dyn Value)),
                                                (&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                                    ::tracing::__macro_support::Option::Some(&method_receiver as
                                                            &dyn Value))])
                            })
                } else {
                    let span =
                        ::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
                    {};
                    span
                }
            };
        __tracing_attr_guard = __tracing_attr_span.enter();
    }

    #[warn(clippy :: suspicious_else_formatting)]
    {

        #[allow(unknown_lints, unreachable_code, clippy ::
        diverging_sub_expression, clippy :: empty_loop, clippy ::
        let_unit_value, clippy :: let_with_type_underscore, clippy ::
        needless_return, clippy :: unreachable)]
        if false {
            let __tracing_attr_fake_return: () = loop {};
            return __tracing_attr_fake_return;
        }
        {
            if !method_receiver {
                for attr in expr.attrs.iter() {
                    self.maybe_emit_expr_attr_err(attr);
                }
            }
            if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
                self.sess.dcx().emit_err(RemoveExprNotSupported {
                        span: attr.span,
                    });
            }
            self.process_cfg_attrs(expr);
            self.try_configure_tokens(&mut *expr);
        }
    }
}#[instrument(level = "trace", skip(self))]
447    pub fn configure_expr(&self, expr: &mut ast::Expr, method_receiver: bool) {
448        if !method_receiver {
449            for attr in expr.attrs.iter() {
450                self.maybe_emit_expr_attr_err(attr);
451            }
452        }
453
454        // If an expr is valid to cfg away it will have been removed by the
455        // outer stmt or expression folder before descending in here.
456        // Anything else is always required, and thus has to error out
457        // in case of a cfg attr.
458        //
459        // N.B., this is intentionally not part of the visit_expr() function
460        //     in order for filter_map_expr() to be able to avoid this check
461        if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
462            self.sess.dcx().emit_err(RemoveExprNotSupported { span: attr.span });
463        }
464
465        self.process_cfg_attrs(expr);
466        self.try_configure_tokens(&mut *expr);
467    }
468}
469
470/// FIXME: Still used by Rustdoc, should be removed after
471pub fn parse_cfg_old<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a MetaItemInner> {
472    let span = meta_item.span;
473    match meta_item.meta_item_list() {
474        None => {
475            sess.dcx().emit_err(InvalidCfg::NotFollowedByParens { span });
476            None
477        }
478        Some([]) => {
479            sess.dcx().emit_err(InvalidCfg::NoPredicate { span });
480            None
481        }
482        Some([_, .., l]) => {
483            sess.dcx().emit_err(InvalidCfg::MultiplePredicates { span: l.span() });
484            None
485        }
486        Some([single]) => match single.meta_item_or_bool() {
487            Some(meta_item) => Some(meta_item),
488            None => {
489                sess.dcx().emit_err(InvalidCfg::PredicateLiteral { span: single.span() });
490                None
491            }
492        },
493    }
494}
495
496fn is_cfg(attr: &Attribute) -> bool {
497    attr.has_name(sym::cfg)
498}