Skip to main content

rustc_attr_parsing/
target_checking.rs

1use std::borrow::Cow;
2
3use rustc_ast::{AttrStyle, Safety};
4use rustc_attr_ir::target::{AssocCtxt, MethodKind, Target};
5use rustc_attr_ir::{AttrItem, Attribute, AttributeKind};
6use rustc_errors::{DiagArgValue, MultiSpan, StashKey};
7use rustc_feature::Features;
8use rustc_lint_defs::builtin::{
9    INVALID_DOC_ATTRIBUTES, MISPLACED_DIAGNOSTIC_ATTRIBUTES, UNUSED_ATTRIBUTES, USELESS_DEPRECATED,
10};
11use rustc_span::{BytePos, FileName, RemapPathScopeComponents, Span, Symbol, sym};
12
13use crate::context::AcceptContext;
14use crate::diagnostics::{
15    InvalidAttrAtCrateLevel, InvalidTarget, InvalidTargetHelp, ItemFollowingInnerAttr,
16    UnsupportedAttributesInWhere,
17};
18use crate::target_checking::Policy::Allow;
19use crate::{AttributeParser, ShouldEmit};
20
21#[derive(#[automatically_derived]impl<'a> ::core::fmt::Debug for AllowedTargets<'a> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::AllowList(__self_0) =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "AllowList", &__self_0),
            Self::AllowListWarnRest(__self_0) =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "AllowListWarnRest", &__self_0),
            Self::ManuallyChecked =>
                ::core::fmt::Formatter::write_str(f, "ManuallyChecked"),
        }
    }
}Debug)]
22pub(crate) enum AllowedTargets<'a> {
23    AllowList(&'a [Policy]),
24    AllowListWarnRest(&'a [Policy]),
25    /// This is useful for argument-dependent target checking.
26    /// If debug assertions are enabled,
27    /// this emits a delayed bug if the `cx.check_target(...)` method is not called during attribute parsing.
28    ManuallyChecked,
29}
30
31pub(crate) enum AllowedResult {
32    Allowed,
33    Warn,
34    Error,
35}
36
37impl AllowedTargets<'_> {
38    pub(crate) fn is_allowed(&self, target: Target) -> AllowedResult {
39        match self {
40            AllowedTargets::AllowList(list) => {
41                if list.contains(&Policy::Allow(target))
42                    || list.contains(&Policy::AllowSilent(target))
43                {
44                    AllowedResult::Allowed
45                } else if list.contains(&Policy::Warn(target)) {
46                    AllowedResult::Warn
47                } else {
48                    AllowedResult::Error
49                }
50            }
51            AllowedTargets::AllowListWarnRest(list) => {
52                if list.contains(&Policy::Allow(target))
53                    || list.contains(&Policy::AllowSilent(target))
54                {
55                    AllowedResult::Allowed
56                } else if list.contains(&Policy::Error(target)) {
57                    AllowedResult::Error
58                } else {
59                    AllowedResult::Warn
60                }
61            }
62            AllowedTargets::ManuallyChecked => ::core::panicking::unreachable_default_msg()unreachable!(),
63        }
64    }
65
66    pub(crate) fn allowed_targets(&self) -> Vec<Target> {
67        match self {
68            AllowedTargets::AllowList(list) | AllowedTargets::AllowListWarnRest(list) => list,
69            AllowedTargets::ManuallyChecked => ::core::panicking::unreachable_default_msg()unreachable!(),
70        }
71        .iter()
72        .filter_map(|target| match target {
73            Policy::Allow(target) => Some(*target),
74            Policy::AllowSilent(_) | Policy::Warn(_) | Policy::Error(_) => None,
75        })
76        .collect()
77    }
78}
79
80/// This policy determines what diagnostics should be emitted based on the `Target` of the attribute.
81#[derive(#[automatically_derived]impl ::core::fmt::Debug for Policy {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        match self {
            Self::Allow(__self_0) =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "Allow",
                    &__self_0),
            Self::AllowSilent(__self_0) =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f,
                    "AllowSilent", &__self_0),
            Self::Warn(__self_0) =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "Warn",
                    &__self_0),
            Self::Error(__self_0) =>
                ::core::fmt::Formatter::debug_struct_field1_finish(f, "Error",
                    &__self_0),
        }
    }
}Debug, #[automatically_derived]impl ::core::cmp::Eq for Policy {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<Target>;
    }
}Eq, #[automatically_derived]impl ::core::marker::StructuralPartialEq for Policy {
}
#[automatically_derived]impl ::core::cmp::PartialEq for Policy {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        ::core::intrinsics::discriminant_value(self) ==
                ::core::intrinsics::discriminant_value(other) &&
            match (self, other) {
                (Self::Allow(__self_0), Self::Allow(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Self::AllowSilent(__self_0), Self::AllowSilent(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Self::Warn(__self_0), Self::Warn(__arg1_0)) =>
                    __self_0 == __arg1_0,
                (Self::Error(__self_0), Self::Error(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => unsafe { ::core::intrinsics::unreachable() }
            }
    }
}PartialEq)]
82pub(crate) enum Policy {
83    /// A target that is allowed.
84    Allow(Target),
85    /// A target that is allowed and not listed in the possible targets.
86    /// This is useful if the target is checked elsewhere.
87    AllowSilent(Target),
88    /// Emits a FCW on this target.
89    /// This is useful if the target was previously allowed but should not be.
90    Warn(Target),
91    /// Emits an error on this target.
92    Error(Target),
93}
94
95impl<'sess> AttributeParser<'sess> {
96    pub(crate) fn check_target(
97        allowed_targets: &AllowedTargets<'_>,
98        attribute_args: &str,
99        cx: &mut AcceptContext<'_, 'sess>,
100    ) {
101        if #[allow(non_exhaustive_omitted_patterns)] match cx.should_emit {
    ShouldEmit::Nothing => true,
    _ => false,
}matches!(cx.should_emit, ShouldEmit::Nothing) {
102            return;
103        }
104
105        if let AllowedTargets::ManuallyChecked = allowed_targets {
106            #[cfg(debug_assertions)]
107            if !cx.has_target_been_checked {
108                cx.dcx().delayed_bug("Attribute target has not been checked");
109            }
110
111            return;
112        }
113
114        // For crate-level attributes we emit a specific set of lints to warn
115        // people about accidentally not using them on the crate.
116        if let AllowedTargets::AllowList(policies) | AllowedTargets::AllowListWarnRest(policies) = allowed_targets
117            // If only crate is `Allow`
118            && policies.iter().filter(|p| #[allow(non_exhaustive_omitted_patterns)] match p {
    Allow(_) => true,
    _ => false,
}matches!(p, Allow(_))).all(|p| *p == Allow(Target::Crate))
119        {
120            Self::check_crate_level(cx, allowed_targets);
121            return;
122        }
123
124        let result = allowed_targets.is_allowed(cx.target);
125        if #[allow(non_exhaustive_omitted_patterns)] match result {
    AllowedResult::Allowed => true,
    _ => false,
}matches!(result, AllowedResult::Allowed) {
126            return;
127        }
128
129        let allowed_targets = allowed_targets.allowed_targets();
130        let (applied, only) = allowed_targets_applied(allowed_targets, cx.target, cx.features);
131        let is_diagnostic_attr = cx.attr_path.segments[0] == sym::diagnostic;
132        let is_lint_check_attr = [sym::allow, sym::expect, sym::deny, sym::warn, sym::forbid]
133            .contains(&cx.attr_path.segments[0]);
134
135        let span = if attribute_args.is_empty() {
136            // Example: for the attribute `#[inline]`, name+attribute_args gives "inline",
137            // and the path span covers `inline` which is just what we want.
138            cx.attr_path.span
139        } else {
140            // Example 1: for the attribute `#[repr(C)]`, name+attribute_args gives
141            // "repr(C)", and the inner span covers `repr(C)` which is just what we want.
142            //
143            // Example 2: for the attribute `#[repr(C, packed)]`, name+attribute_args gives
144            // "repr(C)", and the inner span covers `repr(C, packed)` which doesn't match
145            // exactly but is as close as we can get.
146            cx.inner_span
147        };
148        let target_span = if span.ctxt() == cx.target_span.ctxt() && cx.target != Target::Crate {
149            cx.target_span.shrink_to_lo()
150        } else {
151            span
152        };
153
154        let diag = InvalidTarget {
155            span,
156            attr_span: cx.attr_span,
157            name: cx.attr_path.clone(),
158            target: cx.target.plural_name(),
159            target_span,
160            only: if only { "only " } else { "" },
161            applied: DiagArgValue::StrListSepByAnd(applied.into_iter().map(Cow::Owned).collect()),
162            attribute_args: attribute_args.to_string(),
163            help: Self::target_checking_help(attribute_args, cx),
164            previously_accepted: #[allow(non_exhaustive_omitted_patterns)] match result {
    AllowedResult::Warn => true,
    _ => false,
}matches!(result, AllowedResult::Warn)
165                && !is_diagnostic_attr
166                && !is_lint_check_attr,
167            on_macro_call: #[allow(non_exhaustive_omitted_patterns)] match cx.target {
    Target::MacroCall => true,
    _ => false,
}matches!(cx.target, Target::MacroCall),
168        };
169
170        match result {
171            AllowedResult::Allowed => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Should have early returned above")));
}unreachable!("Should have early returned above"),
172            AllowedResult::Warn => {
173                let lint = if cx.attr_path.segments[0] == sym::deprecated
174                    && ![
175                        Target::Closure,
176                        Target::Expression,
177                        Target::Statement,
178                        Target::Arm,
179                        Target::MacroCall,
180                    ]
181                    .contains(&cx.target)
182                {
183                    USELESS_DEPRECATED
184                } else if is_diagnostic_attr {
185                    MISPLACED_DIAGNOSTIC_ATTRIBUTES
186                } else {
187                    UNUSED_ATTRIBUTES
188                };
189
190                let attr_span = cx.attr_span;
191                cx.emit_lint(lint, diag, attr_span);
192            }
193            AllowedResult::Error => {
194                cx.dcx().emit_err(diag);
195            }
196        }
197    }
198
199    fn target_checking_help(
200        attribute_args: &str,
201        cx: &AcceptContext<'_, '_>,
202    ) -> Option<InvalidTargetHelp> {
203        match &*cx.attr_path.segments {
204            [sym::link_name] if cx.target == Target::Static => {
205                let needs_unsafe_wrapper = #[allow(non_exhaustive_omitted_patterns)] match cx.attr_safety {
    Safety::Default => true,
    _ => false,
}matches!(cx.attr_safety, Safety::Default);
206
207                Some(InvalidTargetHelp::UseExportName {
208                    unsafe_open: needs_unsafe_wrapper.then(|| cx.inner_span.shrink_to_lo()),
209                    name: cx.attr_path.span,
210                    unsafe_close: needs_unsafe_wrapper.then(|| cx.inner_span.shrink_to_hi()),
211                })
212            }
213            [sym::repr] if attribute_args == "(align(...))" => match cx.target {
214                Target::Fn | Target::Method(..) if cx.features().fn_align() => {
215                    Some(InvalidTargetHelp::UseRustcAlign)
216                }
217                Target::Static if cx.features().static_align() => {
218                    Some(InvalidTargetHelp::UseRustcAlignStatic)
219                }
220                _ => None,
221            },
222            _ => None,
223        }
224    }
225
226    pub(crate) fn check_crate_level(
227        cx: &mut AcceptContext<'_, 'sess>,
228        allowed_targets: &AllowedTargets<'_>,
229    ) {
230        let warn = match allowed_targets.is_allowed(cx.target) {
231            AllowedResult::Allowed => return,
232            AllowedResult::Warn => true,
233            AllowedResult::Error => false,
234        };
235
236        let name = cx.attr_path.to_string();
237        let is_used_as_inner = cx.attr_style == AttrStyle::Inner;
238        let target_span = cx.target_span;
239        let attr_span = cx.attr_span;
240
241        let (show_crate_root_help, crate_root_path) = is_used_as_inner
242            .then(|| cx.cx.sess.local_crate_source_file())
243            .flatten()
244            .filter(|src| {
245                !#[allow(non_exhaustive_omitted_patterns)] match cx.cx.sess.source_map().span_to_filename(attr_span)
    {
    FileName::Real(ref name) if name == src => true,
    _ => false,
}matches!(
246                    cx.cx.sess.source_map().span_to_filename(attr_span),
247                    FileName::Real(ref name) if name == src
248                )
249            })
250            .map(|src| {
251                (true, src.path(RemapPathScopeComponents::DIAGNOSTICS).display().to_string())
252            })
253            .unwrap_or_default();
254
255        if name == "doc" {
256            let diag = crate::diagnostics::AttrCrateLevelOnly;
257            if warn {
258                cx.emit_lint(INVALID_DOC_ATTRIBUTES, diag, attr_span);
259            } else {
260                cx.emit_err(diag);
261            }
262            return;
263        }
264
265        let diag = crate::diagnostics::InvalidAttrStyle {
266            name,
267            is_used_as_inner,
268            target_span: (!is_used_as_inner).then_some(target_span),
269            target: cx.target.name(),
270            crate_root_path,
271            show_crate_root_help,
272            span: attr_span,
273        };
274        if warn {
275            cx.emit_lint(UNUSED_ATTRIBUTES, diag, attr_span);
276        } else {
277            cx.emit_err(diag);
278        }
279    }
280
281    // FIXME: Fix "Cannot determine resolution" error and remove built-in macros
282    // from this check.
283    pub(crate) fn check_invalid_crate_level_attr_item(&self, attr: &AttrItem, inner_span: Span) {
284        // Check for builtin attributes at the crate level
285        // which were unsuccessfully resolved due to cannot determine
286        // resolution for the attribute macro error.
287        const ATTRS_TO_CHECK: &[Symbol] =
288            &[sym::derive, sym::test, sym::test_case, sym::global_allocator, sym::bench];
289
290        // FIXME(jdonszelmann): all attrs should be combined here cleaning this up some day.
291        if let Some(name) = ATTRS_TO_CHECK.iter().find(|attr_to_check| #[allow(non_exhaustive_omitted_patterns)] match attr.path.segments.as_ref() {
    [segment] if segment == *attr_to_check => true,
    _ => false,
}matches!(attr.path.segments.as_ref(), [segment] if segment == *attr_to_check)) {
292            let span = attr.span;
293            let name = *name;
294
295            let item = self.first_line_of_next_item(span).map(|span| ItemFollowingInnerAttr { span });
296
297            let err = self.dcx().create_err(InvalidAttrAtCrateLevel {
298                span,
299                pound_to_opening_bracket: span.until(inner_span),
300                name,
301                item,
302            });
303
304            self.dcx().try_steal_replace_and_emit_err(
305                attr.path.span,
306                StashKey::UndeterminedMacroResolution,
307                err,
308            );
309        }
310    }
311
312    fn first_line_of_next_item(&self, span: Span) -> Option<Span> {
313        // We can't exactly call `tcx.hir_free_items()` here because it's too early and querying
314        // this would create a circular dependency. Instead, we resort to getting the original
315        // source code that follows `span` and find the next item from here.
316
317        self.sess()
318            .source_map()
319            .span_to_source(span, |content, _, span_end| {
320                let mut source = &content[span_end..];
321                let initial_source_len = source.len();
322                let span = try {
323                    loop {
324                        let first = source.chars().next()?;
325
326                        if first.is_whitespace() {
327                            let split_idx = source.find(|c: char| !c.is_whitespace())?;
328                            source = &source[split_idx..];
329                        } else if source.starts_with("//") {
330                            let line_idx = source.find('\n')?;
331                            source = &source[line_idx + '\n'.len_utf8()..];
332                        } else if source.starts_with("/*") {
333                            // FIXME: support nested comments.
334                            let close_idx = source.find("*/")?;
335                            source = &source[close_idx + "*/".len()..];
336                        } else if first == '#' {
337                            // FIXME: properly find the end of the attributes in order to accurately
338                            // skip them. This version just consumes the source code until the next
339                            // `]`.
340                            let close_idx = source.find(']')?;
341                            source = &source[close_idx + ']'.len_utf8()..];
342                        } else {
343                            let lo = span_end + initial_source_len - source.len();
344                            let last_line = source.split('\n').next().map(|s| s.trim_end())?;
345
346                            let hi = lo + last_line.len();
347                            let lo = BytePos(lo as u32);
348                            let hi = BytePos(hi as u32);
349                            let next_item_span = Span::new(lo, hi, span.ctxt(), None);
350
351                            break next_item_span;
352                        }
353                    }
354                };
355
356                Ok(span)
357            })
358            .ok()
359            .flatten()
360    }
361
362    pub(crate) fn check_invalid_where_predicate_attrs<'attr>(
363        &self,
364        attrs: impl IntoIterator<Item = &'attr Attribute>,
365    ) {
366        // FIXME(where_clause_attrs): Currently, as the following check shows,
367        // only `#[cfg]` and `#[cfg_attr]` are allowed, but it should be removed
368        // if we allow more attributes (e.g., tool attributes and `allow/deny/warn`)
369        // in where clauses. After that, this function would become useless.
370        let spans = attrs
371            .into_iter()
372            .filter_map(|attr| {
373                match attr {
374                    Attribute::Parsed(AttributeKind::DocComment { span, .. }) => Some(*span),
375                    // FIXME: We shouldn't need to special-case `doc`!
376                    Attribute::Parsed(AttributeKind::Doc(attr)) => Some(attr.first_span),
377                    // Checked during attribute parsing target checking
378                    Attribute::Parsed(_) => None,
379                    Attribute::Tool(attr) | Attribute::DeriveHelper(attr) => Some(attr.span),
380                }
381            })
382            .collect::<Vec<_>>();
383        if !spans.is_empty() {
384            self.dcx()
385                .emit_err(UnsupportedAttributesInWhere { span: MultiSpan::from_spans(spans) });
386        }
387    }
388}
389
390/// Takes a list of `allowed_targets` for an attribute, and the `target` the attribute was applied to.
391/// Does some heuristic-based filtering to remove uninteresting targets, and formats the targets into a string
392pub(crate) fn allowed_targets_applied(
393    mut allowed_targets: Vec<Target>,
394    target: Target,
395    features: Option<&Features>,
396) -> (Vec<String>, bool) {
397    // Remove unstable targets from `allowed_targets` if their features are not enabled
398    if let Some(features) = features {
399        if !features.fn_delegation() {
400            allowed_targets.retain(|t| !#[allow(non_exhaustive_omitted_patterns)] match t {
    Target::Delegation { .. } => true,
    _ => false,
}matches!(t, Target::Delegation { .. }));
401        }
402        if !features.stmt_expr_attributes() {
403            allowed_targets.retain(|t| !#[allow(non_exhaustive_omitted_patterns)] match t {
    Target::Expression | Target::Statement => true,
    _ => false,
}matches!(t, Target::Expression | Target::Statement));
404        }
405        if !features.extern_types() {
406            allowed_targets.retain(|t| !#[allow(non_exhaustive_omitted_patterns)] match t {
    Target::ForeignTy => true,
    _ => false,
}matches!(t, Target::ForeignTy));
407        }
408    }
409
410    // We define groups of "similar" targets.
411    // If at least two of the targets are allowed, and the `target` is not in the group,
412    // we collapse the entire group to a single entry to simplify the target list
413    const FUNCTION_LIKE: &[Target] = &[
414        Target::Fn,
415        Target::Closure,
416        Target::ForeignFn,
417        Target::Method(MethodKind::Inherent),
418        Target::Method(MethodKind::Trait { body: false }),
419        Target::Method(MethodKind::Trait { body: true }),
420        Target::Method(MethodKind::TraitImpl),
421    ];
422    const FUNCTION_WITH_BODY_LIKE: &[Target] = &[
423        Target::Fn,
424        Target::Closure,
425        Target::Method(MethodKind::Inherent),
426        Target::Method(MethodKind::Trait { body: true }),
427        Target::Method(MethodKind::TraitImpl),
428    ];
429    const METHOD_LIKE: &[Target] = &[
430        Target::Method(MethodKind::Inherent),
431        Target::Method(MethodKind::Trait { body: false }),
432        Target::Method(MethodKind::Trait { body: true }),
433        Target::Method(MethodKind::TraitImpl),
434    ];
435    const IMPL_LIKE: &[Target] =
436        &[Target::Impl { of_trait: false }, Target::Impl { of_trait: true }];
437    const ADT_LIKE: &[Target] = &[Target::Struct, Target::Enum, Target::Union];
438
439    let mut added_fake_targets = Vec::new();
440    filter_targets(
441        &mut allowed_targets,
442        FUNCTION_LIKE,
443        "functions",
444        target,
445        &mut added_fake_targets,
446    );
447    filter_targets(
448        &mut allowed_targets,
449        FUNCTION_WITH_BODY_LIKE,
450        "functions with a body",
451        target,
452        &mut added_fake_targets,
453    );
454    filter_targets(&mut allowed_targets, METHOD_LIKE, "methods", target, &mut added_fake_targets);
455    filter_targets(&mut allowed_targets, IMPL_LIKE, "impl blocks", target, &mut added_fake_targets);
456    filter_targets(&mut allowed_targets, ADT_LIKE, "data types", target, &mut added_fake_targets);
457
458    let mut target_strings: Vec<_> = added_fake_targets
459        .iter()
460        .copied()
461        .chain(allowed_targets.iter().map(|t| t.plural_name()))
462        .map(|i| i.to_string())
463        .collect();
464
465    // ensure a consistent order
466    target_strings.sort();
467    target_strings.dedup();
468
469    // If there is now only 1 target left, show that as the only possible target
470    let only_target = target_strings.len() == 1;
471
472    (target_strings, only_target)
473}
474
475fn filter_targets(
476    allowed_targets: &mut Vec<Target>,
477    target_group: &'static [Target],
478    target_group_name: &'static str,
479    target: Target,
480    added_fake_targets: &mut Vec<&'static str>,
481) {
482    if target_group.contains(&target) {
483        return;
484    }
485    if allowed_targets.iter().filter(|at| target_group.contains(at)).count() < 2 {
486        return;
487    }
488    allowed_targets.retain(|t| !target_group.contains(t));
489    added_fake_targets.push(target_group_name);
490}
491
492impl<'f, 'sess> AcceptContext<'f, 'sess> {
493    pub(crate) fn check_target(
494        &mut self,
495        attribute_args: &str,
496        allowed_targets: &AllowedTargets<'_>,
497    ) {
498        self.ignore_target_checks();
499        AttributeParser::check_target(allowed_targets, attribute_args, self);
500    }
501
502    pub(crate) fn ignore_target_checks(&mut self) {
503        #[cfg(debug_assertions)]
504        {
505            self.has_target_been_checked = true;
506        }
507    }
508}
509
510/// This is the list of all targets to which a attribute can be applied
511/// This is used for:
512/// - `rustc_dummy`, which can be applied to all targets
513/// - Attributes that are not parted to the new target system yet can use this list as a placeholder
514pub(crate) const ALL_TARGETS: &[Policy] = {
515    use Policy::Allow;
516    &[
517        Allow(Target::ExternCrate),
518        Allow(Target::Use),
519        Allow(Target::Static),
520        Allow(Target::Const),
521        Allow(Target::Fn),
522        Allow(Target::Closure),
523        Allow(Target::Mod),
524        Allow(Target::ForeignMod),
525        Allow(Target::GlobalAsm),
526        Allow(Target::TyAlias),
527        Allow(Target::Enum),
528        Allow(Target::Variant),
529        Allow(Target::Struct),
530        Allow(Target::Field),
531        Allow(Target::Union),
532        Allow(Target::Trait),
533        Allow(Target::TraitAlias),
534        Allow(Target::Impl { of_trait: false }),
535        Allow(Target::Impl { of_trait: true }),
536        Allow(Target::Expression),
537        Allow(Target::Statement),
538        Allow(Target::Arm),
539        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: false })),
540        Allow(Target::AssocConst(AssocCtxt::Trait)),
541        Allow(Target::AssocConst(AssocCtxt::Impl { of_trait: true })),
542        Allow(Target::Method(MethodKind::Inherent)),
543        Allow(Target::Method(MethodKind::Trait { body: false })),
544        Allow(Target::Method(MethodKind::Trait { body: true })),
545        Allow(Target::Method(MethodKind::TraitImpl)),
546        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: false })),
547        Allow(Target::AssocTy(AssocCtxt::Trait)),
548        Allow(Target::AssocTy(AssocCtxt::Impl { of_trait: true })),
549        Allow(Target::ForeignFn),
550        Allow(Target::ForeignStatic),
551        Allow(Target::ForeignTy),
552        Allow(Target::MacroDef),
553        Allow(Target::Param),
554        Allow(Target::PatField),
555        Allow(Target::ExprField),
556        Allow(Target::WherePredicate),
557        Allow(Target::MacroCall),
558        Allow(Target::Crate),
559        Allow(Target::Delegation { mac: false }),
560        Allow(Target::Delegation { mac: true }),
561        Allow(Target::ConstParam),
562        Allow(Target::LifetimeParam),
563        Allow(Target::TypeParam),
564        Allow(Target::Loop),
565        Allow(Target::ForLoop),
566        Allow(Target::While),
567        Allow(Target::Break),
568    ]
569};