Attributes come in two types: inert (or built-in) and active (non-builtin). Inert attributes are parsed during AST lowering to the HIR, while active attributes are expanded during expansion. For more information about the difference, see the page about attributes.
During AST lowering, inert attributes are converted from an unparsed TokenStream to a parsed representation. The parsed form is defined in the rustc_hir crate, and the parsers are defined in the rustc_attr_parsing crate.
AttributeKind in the hir definition of attributes. This will define the parsed form of the attribute that the attribute parser will produce.rustc_hir/attrs/encode_cross_crate.rs, which should return whether your attribute should be visible in dependent crates. This is usually No for code-gen related attributes, and Yes for analysis related attributes.rustc_attr_parsing/attributes/*.rs that will hold the state for your attribute parser. For most parsers this will be an empty struct.NoArgsAttributeParser for attributes that may appear only a single time per item, and take no arguments. For example #[no_mangle].SingleAttributeParser for attributes that may appear only a single time per item, and may take arguments. For example #[inline(...)].CombineAttributeParser for attributes that may appear multiple times per item, and whose occurrences are combined into a single parsed attribute. For example #[feature(...)].AttributeParser for attributes that don't fit cleanly into one of the above traits. For example when multiple different attributes need to be combined into a parsed attribute (such as #[stable] and #[unstable]),PATH: The name of the attribute that is addedTEMPLATE: A structural description of your attribute, used only to guide diagnostics. Use the template! macro to construct this type.STABILITY: Whether your attribute is stable (ungated) or unstable (feature gated).ALLOWED_TARGETS: Which targets the attribute may appear on. For new attributes, all incorrect targets should error, so use the AllowedTargets::AllowList for new attributes, and only use Policy::Allow to allow targets.ON_DUPLICATE: Controls the behavior when the attribute incorrectly appears multiple times. Should usually be OnDuplicate::Error for new attributes, this is the default.SAFETY: Controls whether using the attribute requires marking it as unsafe, such as #[unsafe(no_mangle)]. Should usually be AttributeSafety::Normal, this is the default.AcceptContext providing the context in which the attribute is used, and ArgParser which contains the arguments that were provided to the attribute. When the arguments are incorrect, you should emit an error using the suite of cx.adcx().expected_* function and then return None. Sometimes these two steps can be combined, using the cx.expect_* suite of functions, on which you can use the ? operator to early-return. The attribute parser should do all checks that are possible to ensure the attribute is valid, before returning the parsed attribute.rustc_passes/check_attr.rs. This code is ran right after the HIR is fully built, so it has access to the full HIR for analysis.There are two ways of using an attribute parser, referred to as Early and Late attribute parsing.
To use the parsed representation after the HIR is built, use the find_attr! macro defined here. This macro can be used in the following ways:
find_attr!(tcx, <def_id>, Variant(...)) to find an attribute on a def id.find_attr!(tcx, <hir_id>, Variant(...)) to find an attribute on a HIR id.find_attr!(tcx, crate, Variant(...)) to find an attribute on the current crate.find_attr!(attrs, Variant(...)) to find an attribute in attrs, a &[hir::Attribute].Variant is a pattern matching one of the AttributeKind variants, and can take one of the following shapes:
find_attr!(..., Variant) will return a boolean representing whether the attribute is present.find_attr!(..., Variant(a, b, _) => (a, b)) will return the value after the =>, constructed from fields bound by the pattern.To use the parsed representation before the HIR is built, you usually need to use the AttributeParser::parse_limited function. This function takes a slice of &[ast::Attribute]s, and the name of an attribute you're interested in, and parses the attribute if it is present.
No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while errors will be emitted as a delayed bugs. In other words, we expect attributes parsed with parse_limited to be reparsed later during ast lowering where we do emit the errors.