Revert #154808 because it is based on #152369

This reverts commit 0c94559d48, reversing
changes made to 33528612ba.
This commit is contained in:
Jonathan Brouwer
2026-04-09 18:22:12 +02:00
parent 4c4205163a
commit 30107e89e6
10 changed files with 1252 additions and 269 deletions
@@ -1,14 +1,15 @@
//! Meta-syntax validation logic of attributes for post-expansion.
use std::convert::identity;
use std::slice;
use rustc_ast::token::Delimiter;
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::{
self as ast, AttrArgs, Attribute, DelimArgs, MetaItem, MetaItemInner, MetaItemKind, Safety,
};
use rustc_errors::{Applicability, PResult};
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP};
use rustc_errors::{Applicability, FatalError, PResult};
use rustc_feature::{AttributeTemplate, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
use rustc_hir::AttrPath;
use rustc_hir::lints::AttributeLintKind;
use rustc_parse::parse_in;
@@ -17,23 +18,43 @@
use rustc_session::parse::ParseSess;
use rustc_span::{Span, Symbol, sym};
use crate::session_diagnostics as errors;
use crate::{AttributeParser, Late, session_diagnostics as errors};
pub fn check_attr(psess: &ParseSess, attr: &Attribute) {
// Built-in attributes are parsed in their respective attribute parsers, so can be ignored here
if attr.is_doc_comment()
|| attr.name().is_some_and(|name| BUILTIN_ATTRIBUTE_MAP.contains_key(&name))
if attr.is_doc_comment() || attr.has_name(sym::cfg_trace) || attr.has_name(sym::cfg_attr_trace)
{
return;
}
let attr_item = attr.get_normal_item();
if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
// All key-value attributes are restricted to meta-item syntax.
match parse_meta(psess, attr) {
Ok(_) => {}
Err(err) => {
err.emit();
let builtin_attr_info = attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name));
// Check input tokens for built-in and key-value attributes.
match builtin_attr_info {
// `rustc_dummy` doesn't have any restrictions specific to built-in attributes.
Some(BuiltinAttribute { name, template, .. }) => {
if AttributeParser::<Late>::is_parsed_attribute(slice::from_ref(&name)) {
return;
}
match parse_meta(psess, attr) {
// Don't check safety again, we just did that
Ok(meta) => {
check_builtin_meta_item(psess, &meta, attr.style, *name, *template, false)
}
Err(err) => {
err.emit();
}
}
}
_ => {
let attr_item = attr.get_normal_item();
if let AttrArgs::Eq { .. } = attr_item.args.unparsed_ref().unwrap() {
// All key-value attributes are restricted to meta-item syntax.
match parse_meta(psess, attr) {
Ok(_) => {}
Err(err) => {
err.emit();
}
}
}
}
}
@@ -148,7 +169,7 @@ pub fn check_builtin_meta_item(
}
}
pub fn emit_malformed_attribute(
fn emit_malformed_attribute(
psess: &ParseSess,
style: ast::AttrStyle,
span: Span,
@@ -210,3 +231,15 @@ pub fn emit_malformed_attribute(
err.emit();
}
}
pub fn emit_fatal_malformed_builtin_attribute(
psess: &ParseSess,
attr: &Attribute,
name: Symbol,
) -> ! {
let template = BUILTIN_ATTRIBUTE_MAP.get(&name).expect("builtin attr defined").template;
emit_malformed_attribute(psess, attr.style, attr.span, name, template);
// This is fatal, otherwise it will likely cause a cascade of other errors
// (and an error here is expected to be very rare).
FatalError.raise()
}
+18
View File
@@ -603,3 +603,21 @@ pub(crate) struct TrailingMacro {
pub is_trailing: bool,
pub name: Ident,
}
#[derive(Diagnostic)]
#[diag("unused attribute `{$attr_name}`")]
pub(crate) struct UnusedBuiltinAttribute {
#[note(
"the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}`"
)]
pub invoc_span: Span,
pub attr_name: Symbol,
pub macro_name: String,
#[suggestion(
"remove the attribute",
code = "",
applicability = "machine-applicable",
style = "tool-only"
)]
pub attr_span: Span,
}
+18 -3
View File
@@ -15,8 +15,8 @@
use rustc_ast_pretty::pprust;
use rustc_attr_parsing::parser::AllowExprMetavar;
use rustc_attr_parsing::{
AttributeParser, CFG_TEMPLATE, EvalConfigResult, ShouldEmit, eval_config_entry, parse_cfg,
validate_attr,
AttributeParser, CFG_TEMPLATE, Early, EvalConfigResult, ShouldEmit, eval_config_entry,
parse_cfg, validate_attr,
};
use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -30,7 +30,7 @@
RecoverColon, RecoverComma, Recovery, token_descr,
};
use rustc_session::Session;
use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS;
use rustc_session::lint::builtin::{UNUSED_ATTRIBUTES, UNUSED_DOC_COMMENTS};
use rustc_session::parse::feature_err;
use rustc_span::hygiene::SyntaxContext;
use rustc_span::{ErrorGuaranteed, FileName, Ident, LocalExpnId, Span, Symbol, sym};
@@ -2274,6 +2274,21 @@ fn check_attributes(&self, attrs: &[ast::Attribute], call: &ast::MacCall) {
self.cx.current_expansion.lint_node_id,
crate::errors::MacroCallUnusedDocComment { span: attr.span },
);
} else if rustc_attr_parsing::is_builtin_attr(attr)
&& !AttributeParser::<Early>::is_parsed_attribute(&attr.path())
{
let attr_name = attr.name().unwrap();
self.cx.sess.psess.buffer_lint(
UNUSED_ATTRIBUTES,
attr.span,
self.cx.current_expansion.lint_node_id,
crate::errors::UnusedBuiltinAttribute {
attr_name,
macro_name: pprust::path_to_string(&call.path),
invoc_span: call.path.span,
attr_span: attr.span,
},
);
}
}
}
+2 -15
View File
@@ -2,14 +2,12 @@
use std::path::{self, Path, PathBuf};
use rustc_ast::{AttrVec, Attribute, Inline, Item, ModSpans};
use rustc_attr_parsing::validate_attr::emit_malformed_attribute;
use rustc_attr_parsing::validate_attr;
use rustc_errors::{Diag, ErrorGuaranteed};
use rustc_feature::template;
use rustc_parse::lexer::StripTokens;
use rustc_parse::{exp, new_parser_from_file, unwrap_or_emit_fatal};
use rustc_session::Session;
use rustc_session::parse::ParseSess;
use rustc_span::fatal_error::FatalError;
use rustc_span::{Ident, Span, sym};
use thin_vec::ThinVec;
@@ -186,7 +184,6 @@ pub(crate) fn mod_file_path_from_attr(
attrs: &[Attribute],
dir_path: &Path,
) -> Option<PathBuf> {
// FIXME(154781) use a parsed attribute here
// Extract path string from first `#[path = "path_string"]` attribute.
let first_path = attrs.iter().find(|at| at.has_name(sym::path))?;
let Some(path_sym) = first_path.value_str() else {
@@ -198,17 +195,7 @@ pub(crate) fn mod_file_path_from_attr(
// Usually bad forms are checked during semantic analysis via
// `TyCtxt::check_mod_attrs`), but by the time that runs the macro
// is expanded, and it doesn't give an error.
emit_malformed_attribute(
&sess.psess,
first_path.style,
first_path.span,
sym::path,
template!(
NameValueStr: "file",
"https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"
),
);
FatalError.raise()
validate_attr::emit_fatal_malformed_builtin_attribute(&sess.psess, first_path, sym::path);
};
let path_str = path_sym.as_str();
+1005 -231
View File
@@ -2,9 +2,12 @@
use std::sync::LazyLock;
use AttributeDuplicates::*;
use AttributeGate::*;
use AttributeType::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::AttrStyle;
use rustc_hir::attrs::EncodeCrossCrate;
use rustc_span::edition::Edition;
use rustc_span::{Symbol, sym};
@@ -70,10 +73,21 @@ pub fn find_gated_cfg(pred: impl Fn(Symbol) -> bool) -> Option<&'static GatedCfg
// move that documentation into the relevant place in the other docs, and
// remove the chapter on the flag.
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AttributeType {
/// Normal, builtin attribute that is consumed
/// by the compiler before the unused_attribute check
Normal,
/// Builtin attribute that is only allowed at the crate level
CrateLevel,
}
#[derive(Copy, Clone, PartialEq, Debug)]
pub enum AttributeSafety {
/// Normal attribute that does not need `#[unsafe(...)]`
Normal,
/// Unsafe attribute that requires safety obligations to be discharged.
///
/// An error is emitted when `#[unsafe(...)]` is omitted, except when the attribute's edition
@@ -167,6 +181,57 @@ pub fn suggestions(
}
}
/// How to handle multiple duplicate attributes on the same item.
#[derive(Clone, Copy, Default)]
pub enum AttributeDuplicates {
/// Duplicates of this attribute are allowed.
///
/// This should only be used with attributes where duplicates have semantic
/// meaning, or some kind of "additive" behavior. For example, `#[warn(..)]`
/// can be specified multiple times, and it combines all the entries. Or use
/// this if there is validation done elsewhere.
#[default]
DuplicatesOk,
/// Duplicates after the first attribute will be an unused_attribute warning.
///
/// This is usually used for "word" attributes, where they are used as a
/// boolean marker, like `#[used]`. It is not necessarily wrong that there
/// are duplicates, but the others should probably be removed.
WarnFollowing,
/// Same as `WarnFollowing`, but only issues warnings for word-style attributes.
///
/// This is only for special cases, for example multiple `#[macro_use]` can
/// be warned, but multiple `#[macro_use(...)]` should not because the list
/// form has different meaning from the word form.
WarnFollowingWordOnly,
/// Duplicates after the first attribute will be an error.
///
/// This should be used where duplicates would be ignored, but carry extra
/// meaning that could cause confusion. For example, `#[stable(since="1.0")]
/// #[stable(since="2.0")]`, which version should be used for `stable`?
ErrorFollowing,
/// Duplicates preceding the last instance of the attribute will be an error.
///
/// This is the same as `ErrorFollowing`, except the last attribute is the
/// one that is "used". This is typically used in cases like codegen
/// attributes which usually only honor the last attribute.
ErrorPreceding,
/// Duplicates after the first attribute will be an unused_attribute warning
/// with a note that this will be an error in the future.
///
/// This should be used for attributes that should be `ErrorFollowing`, but
/// because older versions of rustc silently accepted (and ignored) the
/// attributes, this is used to transition.
FutureWarnFollowing,
/// Duplicates preceding the last instance of the attribute will be a
/// warning, with a note that this will be an error in the future.
///
/// This is the same as `FutureWarnFollowing`, except the last attribute is
/// the one that is "used". Ideally these can eventually migrate to
/// `ErrorPreceding`.
FutureWarnPreceding,
}
/// A convenience macro for constructing attribute templates.
/// E.g., `template!(Word, List: "description")` means that the attribute
/// supports forms `#[attr]` and `#[attr(description)]`.
@@ -203,31 +268,50 @@ macro_rules! template {
}
macro_rules! ungated {
(unsafe($edition:ident) $attr:ident $(,)?) => {
(unsafe($edition:ident) $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe { unsafe_since: Some(Edition::$edition) },
template: $tpl,
gate: Ungated,
duplicates: $duplicates,
}
};
(unsafe $attr:ident $(,)?) => {
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
gate: Ungated,
duplicates: $duplicates,
}
};
($attr:ident $(,)?) => {
BuiltinAttribute { name: sym::$attr, safety: AttributeSafety::Normal, gate: Ungated }
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Normal,
template: $tpl,
gate: Ungated,
duplicates: $duplicates,
}
};
}
macro_rules! gated {
(unsafe $attr:ident, $gate:ident, $message:expr $(,)?) => {
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated {
feature: sym::$gate,
message: $message,
@@ -236,11 +320,14 @@ macro_rules! gated {
},
}
};
(unsafe $attr:ident, $message:expr $(,)?) => {
(unsafe $attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Unsafe { unsafe_since: None },
template: $tpl,
duplicates: $duplicates,
gate: Gated {
feature: sym::$attr,
message: $message,
@@ -249,11 +336,14 @@ macro_rules! gated {
},
}
};
($attr:ident, $gate:ident, $message:expr $(,)?) => {
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $gate:ident, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Normal,
template: $tpl,
duplicates: $duplicates,
gate: Gated {
feature: sym::$gate,
message: $message,
@@ -262,11 +352,14 @@ macro_rules! gated {
},
}
};
($attr:ident, $message:expr $(,)?) => {
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $message:expr $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Normal,
template: $tpl,
duplicates: $duplicates,
gate: Gated {
feature: sym::$attr,
message: $message,
@@ -278,8 +371,13 @@ macro_rules! gated {
}
macro_rules! rustc_attr {
(TEST, $attr:ident $(,)?) => {
rustc_attr!( $attr,
(TEST, $attr:ident, $typ:expr, $tpl:expr, $duplicate:expr, $encode_cross_crate:expr $(,)?) => {
rustc_attr!(
$attr,
$typ,
$tpl,
$duplicate,
$encode_cross_crate,
concat!(
"the `#[",
stringify!($attr),
@@ -287,10 +385,14 @@ macro_rules! rustc_attr {
),
)
};
($attr:ident $(, $notes:expr)* $(,)?) => {
($attr:ident, $typ:expr, $tpl:expr, $duplicates:expr, $encode_cross_crate:expr, $($notes:expr),* $(,)?) => {
BuiltinAttribute {
name: sym::$attr,
encode_cross_crate: $encode_cross_crate,
type_: $typ,
safety: AttributeSafety::Normal,
template: $tpl,
duplicates: $duplicates,
gate: Gated {
feature: sym::rustc_attrs,
message: "use of an internal attribute",
@@ -314,7 +416,15 @@ macro_rules! experimental {
pub struct BuiltinAttribute {
pub name: Symbol,
/// Whether this attribute is encode cross crate.
///
/// If so, it is encoded in the crate metadata.
/// Otherwise, it can only be used in the local crate.
pub encode_cross_crate: EncodeCrossCrate,
pub type_: AttributeType,
pub safety: AttributeSafety,
pub template: AttributeTemplate,
pub duplicates: AttributeDuplicates,
pub gate: AttributeGate,
}
@@ -326,100 +436,379 @@ pub struct BuiltinAttribute {
// ==========================================================================
// Conditional compilation:
ungated!(cfg),
ungated!(cfg_attr),
ungated!(
cfg, Normal,
template!(
List: &["predicate"],
"https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute"
),
DuplicatesOk, EncodeCrossCrate::No
),
ungated!(
cfg_attr, Normal,
template!(
List: &["predicate, attr1, attr2, ..."],
"https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute"
),
DuplicatesOk, EncodeCrossCrate::No
),
// Testing:
ungated!(ignore),
ungated!(should_panic),
ungated!(
ignore, Normal,
template!(
Word,
NameValueStr: "reason",
"https://doc.rust-lang.org/reference/attributes/testing.html#the-ignore-attribute"
),
WarnFollowing, EncodeCrossCrate::No,
),
ungated!(
should_panic, Normal,
template!(
Word,
List: &[r#"expected = "reason""#],
NameValueStr: "reason",
"https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute"
),
FutureWarnFollowing, EncodeCrossCrate::No,
),
// Macros:
ungated!(automatically_derived),
ungated!(macro_use),
ungated!(macro_escape), // Deprecated synonym for `macro_use`.
ungated!(macro_export),
ungated!(proc_macro),
ungated!(proc_macro_derive),
ungated!(proc_macro_attribute),
ungated!(
automatically_derived, Normal,
template!(
Word,
"https://doc.rust-lang.org/reference/attributes/derive.html#the-automatically_derived-attribute"
),
WarnFollowing, EncodeCrossCrate::Yes
),
ungated!(
macro_use, Normal,
template!(
Word,
List: &["name1, name2, ..."],
"https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute"
),
WarnFollowingWordOnly, EncodeCrossCrate::No,
),
ungated!(macro_escape, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No), // Deprecated synonym for `macro_use`.
ungated!(
macro_export, Normal,
template!(
Word,
List: &["local_inner_macros"],
"https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope"
),
WarnFollowing, EncodeCrossCrate::Yes
),
ungated!(
proc_macro, Normal,
template!(
Word,
"https://doc.rust-lang.org/reference/procedural-macros.html#function-like-procedural-macros"),
ErrorFollowing, EncodeCrossCrate::No
),
ungated!(
proc_macro_derive, Normal,
template!(
List: &["TraitName", "TraitName, attributes(name1, name2, ...)"],
"https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros"
),
ErrorFollowing, EncodeCrossCrate::No,
),
ungated!(
proc_macro_attribute, Normal,
template!(Word, "https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros"),
ErrorFollowing, EncodeCrossCrate::No
),
// Lints:
ungated!(warn),
ungated!(allow),
ungated!(expect),
ungated!(forbid),
ungated!(deny),
ungated!(must_use),
gated!(must_not_suspend, experimental!(must_not_suspend)),
ungated!(deprecated),
ungated!(
warn, Normal,
template!(
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
),
DuplicatesOk, EncodeCrossCrate::No,
),
ungated!(
allow, Normal,
template!(
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
),
DuplicatesOk, EncodeCrossCrate::No,
),
ungated!(
expect, Normal,
template!(
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
),
DuplicatesOk, EncodeCrossCrate::No,
),
ungated!(
forbid, Normal,
template!(
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
),
DuplicatesOk, EncodeCrossCrate::No
),
ungated!(
deny, Normal,
template!(
List: &["lint1", "lint1, lint2, ...", r#"lint1, lint2, lint3, reason = "...""#],
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#lint-check-attributes"
),
DuplicatesOk, EncodeCrossCrate::No
),
ungated!(
must_use, Normal,
template!(
Word,
NameValueStr: "reason",
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute"
),
FutureWarnFollowing, EncodeCrossCrate::Yes
),
gated!(
must_not_suspend, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing,
EncodeCrossCrate::Yes, experimental!(must_not_suspend)
),
ungated!(
deprecated, Normal,
template!(
Word,
List: &[r#"/*opt*/ since = "version", /*opt*/ note = "reason""#],
NameValueStr: "reason",
"https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute"
),
ErrorFollowing, EncodeCrossCrate::Yes
),
// Crate properties:
ungated!(crate_name),
ungated!(crate_type),
ungated!(
crate_name, CrateLevel,
template!(
NameValueStr: "name",
"https://doc.rust-lang.org/reference/crates-and-source-files.html#the-crate_name-attribute"
),
FutureWarnFollowing, EncodeCrossCrate::No,
),
ungated!(
crate_type, CrateLevel,
template!(
NameValueStr: ["bin", "lib", "dylib", "cdylib", "rlib", "staticlib", "sdylib", "proc-macro"],
"https://doc.rust-lang.org/reference/linkage.html"
),
DuplicatesOk, EncodeCrossCrate::No,
),
// ABI, linking, symbols, and FFI
ungated!(link),
ungated!(link_name),
ungated!(no_link),
ungated!(repr),
ungated!(
link, Normal,
template!(List: &[
r#"name = "...""#,
r#"name = "...", kind = "dylib|static|...""#,
r#"name = "...", wasm_import_module = "...""#,
r#"name = "...", import_name_type = "decorated|noprefix|undecorated""#,
r#"name = "...", kind = "dylib|static|...", wasm_import_module = "...", import_name_type = "decorated|noprefix|undecorated""#,
], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute"),
DuplicatesOk, EncodeCrossCrate::No,
),
ungated!(
link_name, Normal,
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_name-attribute"),
FutureWarnPreceding, EncodeCrossCrate::Yes
),
ungated!(
no_link, Normal,
template!(Word, "https://doc.rust-lang.org/reference/items/extern-crates.html#the-no_link-attribute"),
WarnFollowing, EncodeCrossCrate::No
),
ungated!(
repr, Normal,
template!(
List: &["C", "Rust", "transparent", "align(...)", "packed(...)", "<integer type>"],
"https://doc.rust-lang.org/reference/type-layout.html#representations"
),
DuplicatesOk, EncodeCrossCrate::No
),
// FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity
gated!(rustc_align,fn_align, experimental!(rustc_align)),
gated!(rustc_align_static,static_align, experimental!(rustc_align_static)),
ungated!(unsafe(Edition2024) export_name),
ungated!(unsafe(Edition2024) link_section),
ungated!(unsafe(Edition2024) no_mangle),
ungated!(used),
ungated!(link_ordinal),
ungated!(unsafe naked),
gated!(rustc_align, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, fn_align, experimental!(rustc_align)),
gated!(rustc_align_static, Normal, template!(List: &["alignment"]), DuplicatesOk, EncodeCrossCrate::No, static_align, experimental!(rustc_align_static)),
ungated!(
unsafe(Edition2024) export_name, Normal,
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-export_name-attribute"),
FutureWarnPreceding, EncodeCrossCrate::No
),
ungated!(
unsafe(Edition2024) link_section, Normal,
template!(NameValueStr: "name", "https://doc.rust-lang.org/reference/abi.html#the-link_section-attribute"),
FutureWarnPreceding, EncodeCrossCrate::No
),
ungated!(
unsafe(Edition2024) no_mangle, Normal,
template!(Word, "https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute"),
WarnFollowing, EncodeCrossCrate::No
),
ungated!(
used, Normal,
template!(Word, List: &["compiler", "linker"], "https://doc.rust-lang.org/reference/abi.html#the-used-attribute"),
WarnFollowing, EncodeCrossCrate::No
),
ungated!(
link_ordinal, Normal,
template!(List: &["ordinal"], "https://doc.rust-lang.org/reference/items/external-blocks.html#the-link_ordinal-attribute"),
ErrorPreceding, EncodeCrossCrate::Yes
),
ungated!(
unsafe naked, Normal,
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-naked-attribute"),
WarnFollowing, EncodeCrossCrate::No
),
// See `TyAndLayout::pass_indirectly_in_non_rustic_abis` for details.
rustc_attr!(rustc_pass_indirectly_in_non_rustic_abis, "types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs"),
rustc_attr!(
rustc_pass_indirectly_in_non_rustic_abis, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No,
"types marked with `#[rustc_pass_indirectly_in_non_rustic_abis]` are always passed indirectly by non-Rustic ABIs"
),
// Limits:
ungated!(recursion_limit),
ungated!(type_length_limit),
ungated!(
recursion_limit, CrateLevel,
template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-recursion_limit-attribute"),
FutureWarnFollowing, EncodeCrossCrate::No
),
ungated!(
type_length_limit, CrateLevel,
template!(NameValueStr: "N", "https://doc.rust-lang.org/reference/attributes/limits.html#the-type_length_limit-attribute"),
FutureWarnFollowing, EncodeCrossCrate::No
),
gated!(
move_size_limit, large_assignments, experimental!(move_size_limit)
move_size_limit, CrateLevel, template!(NameValueStr: "N"), ErrorFollowing,
EncodeCrossCrate::No, large_assignments, experimental!(move_size_limit)
),
// Entry point:
ungated!(no_main),
ungated!(
no_main, CrateLevel,
template!(Word, "https://doc.rust-lang.org/reference/crates-and-source-files.html#the-no_main-attribute"),
WarnFollowing, EncodeCrossCrate::No
),
// Modules, prelude, and resolution:
ungated!(path),
ungated!(no_std),
ungated!(no_implicit_prelude),
ungated!(non_exhaustive),
ungated!(
path, Normal,
template!(NameValueStr: "file", "https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute"),
FutureWarnFollowing, EncodeCrossCrate::No
),
ungated!(
no_std, CrateLevel,
template!(Word, "https://doc.rust-lang.org/reference/names/preludes.html#the-no_std-attribute"),
WarnFollowing, EncodeCrossCrate::No
),
ungated!(
no_implicit_prelude, Normal,
template!(Word, "https://doc.rust-lang.org/reference/names/preludes.html#the-no_implicit_prelude-attribute"),
WarnFollowing, EncodeCrossCrate::No
),
ungated!(
non_exhaustive, Normal,
template!(Word, "https://doc.rust-lang.org/reference/attributes/type_system.html#the-non_exhaustive-attribute"),
WarnFollowing, EncodeCrossCrate::Yes
),
// Runtime
ungated!(windows_subsystem),
ungated!(// RFC 2070
panic_handler
ungated!(
windows_subsystem, CrateLevel,
template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"),
FutureWarnFollowing, EncodeCrossCrate::No
),
ungated!( // RFC 2070
panic_handler, Normal,
template!(Word, "https://doc.rust-lang.org/reference/panic.html#the-panic_handler-attribute"),
WarnFollowing, EncodeCrossCrate::Yes
),
// Code generation:
ungated!(inline),
ungated!(cold),
ungated!(no_builtins),
ungated!(target_feature),
ungated!(track_caller),
ungated!(instruction_set),
gated!(
unsafe force_target_feature,
effective_target_features, experimental!(force_target_feature)
ungated!(
inline, Normal,
template!(
Word,
List: &["always", "never"],
"https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute"
),
FutureWarnFollowing, EncodeCrossCrate::No
),
ungated!(
cold, Normal,
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-cold-attribute"),
WarnFollowing, EncodeCrossCrate::No
),
ungated!(
no_builtins, CrateLevel,
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-no_builtins-attribute"),
WarnFollowing, EncodeCrossCrate::Yes
),
ungated!(
target_feature, Normal,
template!(List: &[r#"enable = "name""#], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-target_feature-attribute"),
DuplicatesOk, EncodeCrossCrate::No,
),
ungated!(
track_caller, Normal,
template!(Word, "https://doc.rust-lang.org/reference/attributes/codegen.html#the-track_caller-attribute"),
WarnFollowing, EncodeCrossCrate::Yes
),
ungated!(
instruction_set, Normal,
template!(List: &["set"], "https://doc.rust-lang.org/reference/attributes/codegen.html#the-instruction_set-attribute"),
ErrorPreceding, EncodeCrossCrate::No
),
gated!(
sanitize,
sanitize, experimental!(sanitize)
unsafe force_target_feature, Normal, template!(List: &[r#"enable = "name""#]),
DuplicatesOk, EncodeCrossCrate::No, effective_target_features, experimental!(force_target_feature)
),
gated!(
coverage,
sanitize, Normal, template!(List: &[r#"address = "on|off""#, r#"kernel_address = "on|off""#, r#"cfi = "on|off""#, r#"hwaddress = "on|off""#, r#"kernel_hwaddress = "on|off""#, r#"kcfi = "on|off""#, r#"memory = "on|off""#, r#"memtag = "on|off""#, r#"shadow_call_stack = "on|off""#, r#"thread = "on|off""#]), ErrorPreceding,
EncodeCrossCrate::No, sanitize, experimental!(sanitize),
),
gated!(
coverage, Normal, template!(OneOf: &[sym::off, sym::on]),
ErrorPreceding, EncodeCrossCrate::No,
coverage_attribute, experimental!(coverage)
),
ungated!(doc),
ungated!(
doc, Normal,
template!(
List: &["hidden", "inline"],
NameValueStr: "string",
"https://doc.rust-lang.org/rustdoc/write-documentation/the-doc-attribute.html"
),
DuplicatesOk, EncodeCrossCrate::Yes
),
// Debugging
ungated!(debugger_visualizer),
ungated!(collapse_debuginfo),
ungated!(
debugger_visualizer, Normal,
template!(
List: &[r#"natvis_file = "...", gdb_script_file = "...""#],
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-debugger_visualizer-attribute"
),
DuplicatesOk, EncodeCrossCrate::No
),
ungated!(
collapse_debuginfo, Normal,
template!(
List: &["no", "external", "yes"],
"https://doc.rust-lang.org/reference/attributes/debugger.html#the-collapse_debuginfo-attribute"
),
ErrorFollowing, EncodeCrossCrate::Yes
),
// ==========================================================================
// Unstable attributes:
@@ -427,61 +816,71 @@ pub struct BuiltinAttribute {
// Linking:
gated!(
export_stable, experimental!(export_stable)
export_stable, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, experimental!(export_stable)
),
// Testing:
gated!(
test_runner, custom_test_frameworks,
"custom test frameworks are an unstable feature"
test_runner, CrateLevel, template!(List: &["path"]), ErrorFollowing,
EncodeCrossCrate::Yes, custom_test_frameworks,
"custom test frameworks are an unstable feature",
),
gated!(
reexport_test_harness_main, custom_test_frameworks,
"custom test frameworks are an unstable feature"
reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name"), ErrorFollowing,
EncodeCrossCrate::No, custom_test_frameworks,
"custom test frameworks are an unstable feature",
),
// RFC #1268
gated!(
marker,marker_trait_attr, experimental!(marker)
marker, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
marker_trait_attr, experimental!(marker)
),
gated!(
thread_local,"`#[thread_local]` is an experimental feature, and does not currently handle destructors"
thread_local, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
"`#[thread_local]` is an experimental feature, and does not currently handle destructors",
),
gated!(
no_core, experimental!(no_core)
no_core, CrateLevel, template!(Word), WarnFollowing,
EncodeCrossCrate::No, experimental!(no_core)
),
// RFC 2412
gated!(
optimize,
optimize_attribute, experimental!(optimize)
optimize, Normal, template!(List: &["none", "size", "speed"]), ErrorPreceding,
EncodeCrossCrate::No, optimize_attribute, experimental!(optimize)
),
gated!(
unsafe ffi_pure, experimental!(ffi_pure)
unsafe ffi_pure, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, experimental!(ffi_pure)
),
gated!(
unsafe ffi_const, experimental!(ffi_const)
unsafe ffi_const, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, experimental!(ffi_const)
),
gated!(
register_tool, experimental!(register_tool)
register_tool, CrateLevel, template!(List: &["tool1, tool2, ..."]), DuplicatesOk,
EncodeCrossCrate::No, experimental!(register_tool),
),
// `#[cfi_encoding = ""]`
gated!(
cfi_encoding,
experimental!(cfi_encoding)
cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
EncodeCrossCrate::Yes, experimental!(cfi_encoding)
),
// `#[coroutine]` attribute to be applied to closures to make them coroutines instead
gated!(
coroutine,coroutines, experimental!(coroutine)
coroutine, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No, coroutines, experimental!(coroutine)
),
// RFC 3543
// `#[patchable_function_entry(prefix_nops = m, entry_nops = n)]`
gated!(
patchable_function_entry,
experimental!(patchable_function_entry)
patchable_function_entry, Normal, template!(List: &["prefix_nops = m, entry_nops = n"]), ErrorPreceding,
EncodeCrossCrate::Yes, experimental!(patchable_function_entry)
),
// The `#[loop_match]` and `#[const_continue]` attributes are part of the
@@ -489,10 +888,12 @@ pub struct BuiltinAttribute {
//
// - https://github.com/rust-lang/rust/issues/132306
gated!(
const_continue,loop_match, experimental!(const_continue)
const_continue, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No, loop_match, experimental!(const_continue)
),
gated!(
loop_match,loop_match, experimental!(loop_match)
loop_match, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::No, loop_match, experimental!(loop_match)
),
// The `#[pin_v2]` attribute is part of the `pin_ergonomics` experiment
@@ -500,40 +901,74 @@ pub struct BuiltinAttribute {
//
// - https://github.com/rust-lang/rust/issues/130494
gated!(
pin_v2,pin_ergonomics, experimental!(pin_v2),
pin_v2, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes, pin_ergonomics, experimental!(pin_v2),
),
// ==========================================================================
// Internal attributes: Stability, deprecation, and unsafe:
// ==========================================================================
ungated!(feature),
ungated!(
feature, CrateLevel,
template!(List: &["name1, name2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
),
// DuplicatesOk since it has its own validation
ungated!(stable),
ungated!(unstable),
ungated!(unstable_feature_bound),
ungated!(rustc_const_unstable),
ungated!(rustc_const_stable),
ungated!(rustc_default_body_unstable),
ungated!(
stable, Normal,
template!(List: &[r#"feature = "name", since = "version""#]), DuplicatesOk, EncodeCrossCrate::No,
),
ungated!(
unstable, Normal,
template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]), DuplicatesOk,
EncodeCrossCrate::Yes
),
ungated!(
unstable_feature_bound, Normal, template!(Word, List: &["feat1, feat2, ..."]),
DuplicatesOk, EncodeCrossCrate::No,
),
ungated!(
rustc_const_unstable, Normal, template!(List: &[r#"feature = "name""#]),
DuplicatesOk, EncodeCrossCrate::Yes
),
ungated!(
rustc_const_stable, Normal,
template!(List: &[r#"feature = "name""#]), DuplicatesOk, EncodeCrossCrate::No,
),
ungated!(
rustc_default_body_unstable, Normal,
template!(List: &[r#"feature = "name", reason = "...", issue = "N""#]),
DuplicatesOk, EncodeCrossCrate::No
),
gated!(
allow_internal_unstable,
allow_internal_unstable, Normal, template!(Word, List: &["feat1, feat2, ..."]),
DuplicatesOk, EncodeCrossCrate::Yes,
"allow_internal_unstable side-steps feature gating and stability checks",
),
gated!(
allow_internal_unsafe, "allow_internal_unsafe side-steps the unsafe_code lint",
allow_internal_unsafe, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, "allow_internal_unsafe side-steps the unsafe_code lint",
),
gated!(
rustc_eii_foreign_item,
eii_internals,
rustc_eii_foreign_item, Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::Yes, eii_internals,
"used internally to mark types with a `transparent` representation when it is guaranteed by the documentation",
),
rustc_attr!(rustc_allowed_through_unstable_modules,
rustc_attr!(
rustc_allowed_through_unstable_modules, Normal, template!(NameValueStr: "deprecation message"),
WarnFollowing, EncodeCrossCrate::No,
"rustc_allowed_through_unstable_modules special cases accidental stabilizations of stable items \
through unstable paths"
),
rustc_attr!(rustc_deprecated_safe_2024,"`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
rustc_attr!(
rustc_deprecated_safe_2024, Normal, template!(List: &[r#"audit_that = "...""#]),
ErrorFollowing, EncodeCrossCrate::Yes,
"`#[rustc_deprecated_safe_2024]` is used to declare functions unsafe across the edition 2024 boundary",
),
rustc_attr!(rustc_pub_transparent,"used internally to mark types with a `transparent` representation when it is guaranteed by the documentation",
rustc_attr!(
rustc_pub_transparent, Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::Yes,
"used internally to mark types with a `transparent` representation when it is guaranteed by the documentation",
),
@@ -541,13 +976,25 @@ pub struct BuiltinAttribute {
// Internal attributes: Type system related:
// ==========================================================================
gated!(fundamental, experimental!(fundamental)),
gated!(fundamental, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes, experimental!(fundamental)),
gated!(
may_dangle, dropck_eyepatch,
"`may_dangle` has unstable semantics and may be removed in the future"
may_dangle, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, dropck_eyepatch,
"`may_dangle` has unstable semantics and may be removed in the future",
),
rustc_attr!(rustc_never_type_options,
rustc_attr!(
rustc_never_type_options,
Normal,
template!(List: &[
"",
r#"fallback = "unit""#,
r#"fallback = "niko""#,
r#"fallback = "never""#,
r#"fallback = "no""#,
]),
ErrorFollowing,
EncodeCrossCrate::No,
"`rustc_never_type_options` is used to experiment with never type fallback and work on \
never type stabilization"
),
@@ -556,33 +1003,57 @@ pub struct BuiltinAttribute {
// Internal attributes: Runtime related:
// ==========================================================================
rustc_attr!(rustc_allocator),
rustc_attr!(rustc_nounwind),
rustc_attr!(rustc_reallocator),
rustc_attr!(rustc_deallocator),
rustc_attr!(rustc_allocator_zeroed),
rustc_attr!(rustc_allocator_zeroed_variant),
gated!(
default_lib_allocator, allocator_internals, experimental!(default_lib_allocator),
rustc_attr!(
rustc_allocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_nounwind, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_reallocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_deallocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_allocator_zeroed, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_allocator_zeroed_variant, Normal, template!(NameValueStr: "function"), ErrorPreceding,
EncodeCrossCrate::Yes,
),
gated!(
needs_allocator, allocator_internals, experimental!(needs_allocator),
default_lib_allocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, allocator_internals, experimental!(default_lib_allocator),
),
gated!(
panic_runtime, experimental!(panic_runtime)
needs_allocator, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, allocator_internals, experimental!(needs_allocator),
),
gated!(
needs_panic_runtime, experimental!(needs_panic_runtime)
panic_runtime, CrateLevel, template!(Word), WarnFollowing,
EncodeCrossCrate::No, experimental!(panic_runtime)
),
gated!(
compiler_builtins,
needs_panic_runtime, CrateLevel, template!(Word), WarnFollowing,
EncodeCrossCrate::No, experimental!(needs_panic_runtime)
),
gated!(
compiler_builtins, CrateLevel, template!(Word), WarnFollowing,
EncodeCrossCrate::No,
"the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
which contains compiler-rt intrinsics and will never be stable"
which contains compiler-rt intrinsics and will never be stable",
),
gated!(
profiler_runtime,
profiler_runtime, CrateLevel, template!(Word), WarnFollowing,
EncodeCrossCrate::No,
"the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
which contains the profiler runtime and will never be stable"
which contains the profiler runtime and will never be stable",
),
// ==========================================================================
@@ -590,123 +1061,277 @@ pub struct BuiltinAttribute {
// ==========================================================================
gated!(
linkage,
"the `linkage` attribute is experimental and not portable across platforms"
linkage, Normal, template!(NameValueStr: [
"available_externally",
"common",
"extern_weak",
"external",
"internal",
"linkonce",
"linkonce_odr",
"weak",
"weak_odr",
], "https://doc.rust-lang.org/reference/linkage.html"),
ErrorPreceding, EncodeCrossCrate::No,
"the `linkage` attribute is experimental and not portable across platforms",
),
rustc_attr!(
rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_objc_class, Normal, template!(NameValueStr: "ClassName"), ErrorPreceding,
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_objc_selector, Normal, template!(NameValueStr: "methodName"), ErrorPreceding,
EncodeCrossCrate::No,
),
rustc_attr!(rustc_std_internal_symbol),
rustc_attr!(rustc_objc_class),
rustc_attr!(rustc_objc_selector),
// ==========================================================================
// Internal attributes, Macro related:
// ==========================================================================
rustc_attr!(rustc_builtin_macro),
rustc_attr!(rustc_proc_macro_decls),
rustc_attr!(rustc_macro_transparency,
"used internally for testing macro hygiene"
rustc_attr!(
rustc_builtin_macro, Normal,
template!(Word, List: &["name", "name, /*opt*/ attributes(name1, name2, ...)"]), ErrorFollowing,
EncodeCrossCrate::Yes,
),
rustc_attr!(
rustc_proc_macro_decls, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No,
),
rustc_attr!(
rustc_macro_transparency, Normal,
template!(NameValueStr: ["transparent", "semiopaque", "opaque"]), ErrorFollowing,
EncodeCrossCrate::Yes, "used internally for testing macro hygiene",
),
rustc_attr!(
rustc_autodiff, Normal,
template!(Word, List: &[r#""...""#]), DuplicatesOk,
EncodeCrossCrate::Yes,
),
rustc_attr!(
rustc_offload_kernel, Normal,
template!(Word), DuplicatesOk,
EncodeCrossCrate::Yes,
),
rustc_attr!(rustc_autodiff),
rustc_attr!(rustc_offload_kernel),
// Traces that are left when `cfg` and `cfg_attr` attributes are expanded.
// The attributes are not gated, to avoid stability errors, but they cannot be used in stable
// or unstable code directly because `sym::cfg_(attr_)trace` are not valid identifiers, they
// can only be generated by the compiler.
ungated!(cfg_trace
ungated!(
cfg_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk,
EncodeCrossCrate::Yes
),
ungated!(cfg_attr_trace
ungated!(
cfg_attr_trace, Normal, template!(Word /* irrelevant */), DuplicatesOk,
EncodeCrossCrate::No
),
// ==========================================================================
// Internal attributes, Diagnostics related:
// ==========================================================================
rustc_attr!(rustc_on_unimplemented,"see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
rustc_attr!(
rustc_on_unimplemented, Normal,
template!(
List: &[r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#],
NameValueStr: "message"
),
ErrorFollowing, EncodeCrossCrate::Yes,
"see `#[diagnostic::on_unimplemented]` for the stable equivalent of this attribute"
),
rustc_attr!(
rustc_confusables, Normal,
template!(List: &[r#""name1", "name2", ..."#]),
ErrorFollowing, EncodeCrossCrate::Yes,
),
rustc_attr!(rustc_confusables),
// Enumerates "identity-like" conversion methods to suggest on type mismatch.
rustc_attr!(rustc_conversion_suggestion),
rustc_attr!(
rustc_conversion_suggestion, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes,
),
// Prevents field reads in the marked trait or method to be considered
// during dead code analysis.
rustc_attr!(rustc_trivial_field_reads),
rustc_attr!(
rustc_trivial_field_reads, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::potential_query_instability` lint to warn methods which
// might not be stable during incremental compilation.
rustc_attr!(rustc_lint_query_instability),
rustc_attr!(
rustc_lint_query_instability, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::untracked_query_information` lint to warn methods which
// might not be stable during incremental compilation.
rustc_attr!(rustc_lint_untracked_query_information),
rustc_attr!(
rustc_lint_untracked_query_information, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::bad_opt_access` lint to identify `DebuggingOptions` and `CodegenOptions`
// types (as well as any others in future).
rustc_attr!(rustc_lint_opt_ty),
rustc_attr!(
rustc_lint_opt_ty, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes,
),
// Used by the `rustc::bad_opt_access` lint on fields
// types (as well as any others in future).
rustc_attr!(rustc_lint_opt_deny_field_access),
rustc_attr!(
rustc_lint_opt_deny_field_access, Normal, template!(List: &["message"]),
WarnFollowing, EncodeCrossCrate::Yes,
),
// ==========================================================================
// Internal attributes, Const related:
// ==========================================================================
rustc_attr!(rustc_promotable),
rustc_attr!(rustc_legacy_const_generics),
rustc_attr!(
rustc_promotable, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, ),
rustc_attr!(
rustc_legacy_const_generics, Normal, template!(List: &["N"]), ErrorFollowing,
EncodeCrossCrate::Yes,
),
// Do not const-check this function's body. It will always get replaced during CTFE via `hook_special_const_fn`.
rustc_attr!(rustc_do_not_const_check, "`#[rustc_do_not_const_check]` skips const-check for this function's body"),
rustc_attr!(rustc_const_stable_indirect,
"this is an internal implementation detail"),
rustc_attr!(rustc_intrinsic_const_stable_indirect,
"this is an internal implementation detail"),
rustc_attr!(rustc_allow_const_fn_unstable,
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
rustc_attr!(
rustc_do_not_const_check, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes, "`#[rustc_do_not_const_check]` skips const-check for this function's body",
),
rustc_attr!(
rustc_const_stable_indirect, Normal,
template!(Word),
WarnFollowing,
EncodeCrossCrate::No,
"this is an internal implementation detail",
),
rustc_attr!(
rustc_intrinsic_const_stable_indirect, Normal,
template!(Word), WarnFollowing, EncodeCrossCrate::No, "this is an internal implementation detail",
),
rustc_attr!(
rustc_allow_const_fn_unstable, Normal,
template!(Word, List: &["feat1, feat2, ..."]), DuplicatesOk, EncodeCrossCrate::No,
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
),
// ==========================================================================
// Internal attributes, Layout related:
// ==========================================================================
rustc_attr!(rustc_layout_scalar_valid_range_start, "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
niche optimizations in the standard library"),
rustc_attr!(rustc_layout_scalar_valid_range_end, "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in the standard library"),
rustc_attr!(rustc_simd_monomorphize_lane_limit, "the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \
for better error messages"),
rustc_attr!(rustc_nonnull_optimization_guaranteed,
rustc_attr!(
rustc_layout_scalar_valid_range_start, Normal, template!(List: &["value"]), ErrorFollowing,
EncodeCrossCrate::Yes,
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
niche optimizations in the standard library",
),
rustc_attr!(
rustc_layout_scalar_valid_range_end, Normal, template!(List: &["value"]), ErrorFollowing,
EncodeCrossCrate::Yes,
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in the standard library",
),
rustc_attr!(
rustc_simd_monomorphize_lane_limit, Normal, template!(NameValueStr: "N"), ErrorFollowing,
EncodeCrossCrate::Yes,
"the `#[rustc_simd_monomorphize_lane_limit]` attribute is just used by std::simd \
for better error messages",
),
rustc_attr!(
rustc_nonnull_optimization_guaranteed, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes,
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to document \
guaranteed niche optimizations in the standard library",
"the compiler does not even check whether the type indeed is being non-null-optimized; \
it is your responsibility to ensure that the attribute is only used on types that are optimized"),
it is your responsibility to ensure that the attribute is only used on types that are optimized",
),
// ==========================================================================
// Internal attributes, Misc:
// ==========================================================================
gated!(
lang,lang_items,
"lang items are subject to change"
lang, Normal, template!(NameValueStr: "name"), DuplicatesOk, EncodeCrossCrate::No, lang_items,
"lang items are subject to change",
),
rustc_attr!(rustc_as_ptr, "`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations"),
rustc_attr!(rustc_should_not_be_called_on_const_items, "`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts"),
rustc_attr!(rustc_pass_by_value, "`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference"),
rustc_attr!(rustc_never_returns_null_ptr, "`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers"),
rustc_attr!(rustc_no_implicit_autorefs, "`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument"),
rustc_attr!(rustc_coherence_is_core, "`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`"),
rustc_attr!(rustc_coinductive, "`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver"),
rustc_attr!(rustc_allow_incoherent_impl, "`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl"),
rustc_attr!(rustc_preserve_ub_checks, "`#![rustc_preserve_ub_checks]` prevents the designated crate from evaluating whether UB checks are enabled when optimizing MIR"),
rustc_attr!(rustc_deny_explicit_impl,
rustc_attr!(
rustc_as_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_as_ptr]` is used to mark functions returning pointers to their inner allocations"
),
rustc_attr!(
rustc_should_not_be_called_on_const_items, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_should_not_be_called_on_const_items]` is used to mark methods that don't make sense to be called on interior mutable consts"
),
rustc_attr!(
rustc_pass_by_value, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_pass_by_value]` is used to mark types that must be passed by value instead of reference"
),
rustc_attr!(
rustc_never_returns_null_ptr, Normal, template!(Word), ErrorFollowing,
EncodeCrossCrate::Yes,
"`#[rustc_never_returns_null_ptr]` is used to mark functions returning non-null pointers"
),
rustc_attr!(
rustc_no_implicit_autorefs, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes,
"`#[rustc_no_implicit_autorefs]` is used to mark functions for which an autoref to the dereference of a raw pointer should not be used as an argument"
),
rustc_attr!(
rustc_coherence_is_core, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
"`#![rustc_coherence_is_core]` allows inherent methods on builtin types, only intended to be used in `core`"
),
rustc_attr!(
rustc_coinductive, AttributeType::Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
"`#[rustc_coinductive]` changes a trait to be coinductive, allowing cycles in the trait solver"
),
rustc_attr!(
rustc_allow_incoherent_impl, AttributeType::Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
"`#[rustc_allow_incoherent_impl]` has to be added to all impl items of an incoherent inherent impl"
),
rustc_attr!(
rustc_preserve_ub_checks, AttributeType::CrateLevel, template!(Word), ErrorFollowing, EncodeCrossCrate::No,
"`#![rustc_preserve_ub_checks]` prevents the designated crate from evaluating whether UB checks are enabled when optimizing MIR",
),
rustc_attr!(
rustc_deny_explicit_impl,
AttributeType::Normal,
template!(Word),
ErrorFollowing,
EncodeCrossCrate::No,
"`#[rustc_deny_explicit_impl]` enforces that a trait can have no user-provided impls"
),
rustc_attr!(rustc_dyn_incompatible_trait,
rustc_attr!(
rustc_dyn_incompatible_trait,
AttributeType::Normal,
template!(Word),
ErrorFollowing,
EncodeCrossCrate::No,
"`#[rustc_dyn_incompatible_trait]` marks a trait as dyn-incompatible, \
even if it otherwise satisfies the requirements to be dyn-compatible."
),
rustc_attr!(rustc_has_incoherent_inherent_impls, "`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
rustc_attr!(
rustc_has_incoherent_inherent_impls, AttributeType::Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::Yes,
"`#[rustc_has_incoherent_inherent_impls]` allows the addition of incoherent inherent impls for \
the given type by annotating all impl items with `#[rustc_allow_incoherent_impl]`"
),
rustc_attr!(rustc_non_const_trait_method, "`#[rustc_non_const_trait_method]` should only used by the standard library to mark trait methods \
rustc_attr!(
rustc_non_const_trait_method, AttributeType::Normal, template!(Word),
ErrorFollowing, EncodeCrossCrate::No,
"`#[rustc_non_const_trait_method]` should only used by the standard library to mark trait methods \
as non-const to allow large traits an easier transition to const"
),
BuiltinAttribute {
name: sym::rustc_diagnostic_item,
// FIXME: This can be `true` once we always use `tcx.is_diagnostic_item`.
encode_cross_crate: EncodeCrossCrate::Yes,
type_: Normal,
safety: AttributeSafety::Normal,
template: template!(NameValueStr: "name"),
duplicates: ErrorFollowing,
gate: Gated {
feature: sym::rustc_attrs,
message: "use of an internal attribute",
@@ -717,87 +1342,236 @@ pub struct BuiltinAttribute {
},
gated!(
// Used in resolve:
prelude_import, "`#[prelude_import]` is for use by rustc only",
prelude_import, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::No, "`#[prelude_import]` is for use by rustc only",
),
gated!(
rustc_paren_sugar,unboxed_closures, "unboxed_closures are still evolving",
rustc_paren_sugar, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
unboxed_closures, "unboxed_closures are still evolving",
),
rustc_attr!(rustc_inherit_overflow_checks,"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
rustc_attr!(
rustc_inherit_overflow_checks, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
overflow checking behavior of several functions in the standard library that are inlined \
across crates"
across crates",
),
rustc_attr!(rustc_reservation_impl,"the `#[rustc_reservation_impl]` attribute is internally used \
rustc_attr!(
rustc_reservation_impl, Normal,
template!(NameValueStr: "reservation message"), ErrorFollowing, EncodeCrossCrate::Yes,
"the `#[rustc_reservation_impl]` attribute is internally used \
for reserving `impl<T> From<!> for T` as part of the effort to stabilize `!`"
),
rustc_attr!(rustc_test_marker, "the `#[rustc_test_marker]` attribute is used internally to track tests"),
rustc_attr!(rustc_unsafe_specialization_marker,
rustc_attr!(
rustc_test_marker, Normal, template!(NameValueStr: "name"), WarnFollowing,
EncodeCrossCrate::No, "the `#[rustc_test_marker]` attribute is used internally to track tests",
),
rustc_attr!(
rustc_unsafe_specialization_marker, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No,
"the `#[rustc_unsafe_specialization_marker]` attribute is used to check specializations"
),
rustc_attr!(rustc_specialization_trait,
rustc_attr!(
rustc_specialization_trait, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No,
"the `#[rustc_specialization_trait]` attribute is used to check specializations"
),
rustc_attr!(rustc_main,"the `#[rustc_main]` attribute is used internally to specify test entry point function"),
rustc_attr!(rustc_skip_during_method_dispatch, "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
rustc_attr!(
rustc_main, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No,
"the `#[rustc_main]` attribute is used internally to specify test entry point function",
),
rustc_attr!(
rustc_skip_during_method_dispatch, Normal, template!(List: &["array, boxed_slice"]), ErrorFollowing,
EncodeCrossCrate::No,
"the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
from method dispatch when the receiver is of the following type, for compatibility in \
editions < 2021 (array) or editions < 2024 (boxed_slice)"
),
rustc_attr!(rustc_must_implement_one_of,"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
rustc_attr!(
rustc_must_implement_one_of, Normal, template!(List: &["function1, function2, ..."]),
ErrorFollowing, EncodeCrossCrate::No,
"the `#[rustc_must_implement_one_of]` attribute is used to change minimal complete \
definition of a trait. Its syntax and semantics are highly experimental and will be \
subject to change before stabilization",
),
rustc_attr!(rustc_doc_primitive,"the `#[rustc_doc_primitive]` attribute is used by the standard library \
rustc_attr!(
rustc_doc_primitive, Normal, template!(NameValueStr: "primitive name"), ErrorFollowing,
EncodeCrossCrate::Yes, "the `#[rustc_doc_primitive]` attribute is used by the standard library \
to provide a way to generate documentation for primitive types",
),
gated!(
rustc_intrinsic,intrinsics,
"the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items"),
rustc_attr!(rustc_no_mir_inline,"`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen"
rustc_intrinsic, Normal, template!(Word), ErrorFollowing, EncodeCrossCrate::Yes, intrinsics,
"the `#[rustc_intrinsic]` attribute is used to declare intrinsics as function items",
),
rustc_attr!(
rustc_no_mir_inline, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes,
"`#[rustc_no_mir_inline]` prevents the MIR inliner from inlining a function while not affecting codegen"
),
rustc_attr!(
rustc_force_inline, Normal, template!(Word, NameValueStr: "reason"), WarnFollowing, EncodeCrossCrate::Yes,
"`#[rustc_force_inline]` forces a free function to be inlined"
),
rustc_attr!(
rustc_scalable_vector, Normal, template!(List: &["count"]), WarnFollowing, EncodeCrossCrate::Yes,
"`#[rustc_scalable_vector]` defines a scalable vector type"
),
rustc_attr!(rustc_force_inline,"`#[rustc_force_inline]` forces a free function to be inlined"),
rustc_attr!(rustc_scalable_vector,"`#[rustc_scalable_vector]` defines a scalable vector type"),
// ==========================================================================
// Internal attributes, Testing:
// ==========================================================================
rustc_attr!(TEST, rustc_effective_visibility),
rustc_attr!(TEST, rustc_dump_inferred_outlives),
rustc_attr!(TEST, rustc_capture_analysis),
rustc_attr!(TEST, rustc_insignificant_dtor),
rustc_attr!(TEST, rustc_no_implicit_bounds),
rustc_attr!(TEST, rustc_strict_coherence),
rustc_attr!(TEST, rustc_dump_variances),
rustc_attr!(TEST, rustc_dump_variances_of_opaques),
rustc_attr!(TEST, rustc_hidden_type_of_opaques),
rustc_attr!(TEST, rustc_layout),
rustc_attr!(TEST, rustc_abi),
rustc_attr!(TEST, rustc_regions),
rustc_attr!(TEST, rustc_delayed_bug_from_inside_query),
rustc_attr!(TEST, rustc_dump_user_args),
rustc_attr!(TEST, rustc_evaluate_where_clauses),
rustc_attr!(TEST, rustc_if_this_changed),
rustc_attr!(TEST, rustc_then_this_would_need),
rustc_attr!(TEST, rustc_clean),
rustc_attr!(TEST, rustc_partition_reused),
rustc_attr!(TEST, rustc_partition_codegened),
rustc_attr!(TEST, rustc_expected_cgu_reuse),
rustc_attr!(TEST, rustc_symbol_name),
rustc_attr!(TEST, rustc_def_path),
rustc_attr!(TEST, rustc_mir),
gated!(custom_mir,"the `#[custom_mir]` attribute is just used for the Rust test suite"),
rustc_attr!(TEST, rustc_dump_item_bounds),
rustc_attr!(TEST, rustc_dump_predicates),
rustc_attr!(TEST, rustc_dump_def_parents),
rustc_attr!(TEST, rustc_dump_object_lifetime_defaults),
rustc_attr!(TEST, rustc_dump_vtable),
rustc_attr!(TEST, rustc_dummy),
rustc_attr!(TEST, pattern_complexity_limit),
rustc_attr!(TEST, rustc_effective_visibility, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::Yes),
rustc_attr!(
TEST, rustc_dump_inferred_outlives, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_capture_analysis, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_insignificant_dtor, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes
),
rustc_attr!(
TEST, rustc_no_implicit_bounds, CrateLevel, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_strict_coherence, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::Yes
),
rustc_attr!(
TEST, rustc_dump_variances, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_dump_variances_of_opaques, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_hidden_type_of_opaques, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_layout, Normal, template!(List: &["field1, field2, ..."]),
WarnFollowing, EncodeCrossCrate::Yes
),
rustc_attr!(
TEST, rustc_abi, Normal, template!(List: &["field1, field2, ..."]),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_regions, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_delayed_bug_from_inside_query, Normal,
template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_dump_user_args, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing,
EncodeCrossCrate::Yes
),
rustc_attr!(
TEST, rustc_if_this_changed, Normal, template!(Word, List: &["DepNode"]), DuplicatesOk,
EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_then_this_would_need, Normal, template!(List: &["DepNode"]), DuplicatesOk,
EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_clean, Normal,
template!(List: &[r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#]),
DuplicatesOk, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_partition_reused, Normal,
template!(List: &[r#"cfg = "...", module = "...""#]), DuplicatesOk, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_partition_codegened, Normal,
template!(List: &[r#"cfg = "...", module = "...""#]), DuplicatesOk, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_expected_cgu_reuse, Normal,
template!(List: &[r#"cfg = "...", module = "...", kind = "...""#]), DuplicatesOk,
EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_symbol_name, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_def_path, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_mir, Normal, template!(List: &["arg1, arg2, ..."]),
DuplicatesOk, EncodeCrossCrate::Yes
),
gated!(
custom_mir, Normal, template!(List: &[r#"dialect = "...", phase = "...""#]),
ErrorFollowing, EncodeCrossCrate::No,
"the `#[custom_mir]` attribute is just used for the Rust test suite",
),
rustc_attr!(
TEST, rustc_dump_item_bounds, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_dump_predicates, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_dump_def_parents, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_dump_object_lifetime_defaults, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_dump_vtable, Normal, template!(Word),
WarnFollowing, EncodeCrossCrate::No
),
rustc_attr!(
TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/),
DuplicatesOk, EncodeCrossCrate::No
),
rustc_attr!(
TEST, pattern_complexity_limit, CrateLevel, template!(NameValueStr: "N"),
ErrorFollowing, EncodeCrossCrate::No,
),
];
pub fn is_builtin_attr_name(name: Symbol) -> bool {
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
}
/// Whether this builtin attribute is encoded cross crate.
/// This means it can be used cross crate.
pub fn encode_cross_crate(name: Symbol) -> bool {
if let Some(attr) = BUILTIN_ATTRIBUTE_MAP.get(&name) {
attr.encode_cross_crate == EncodeCrossCrate::Yes
} else {
true
}
}
pub fn is_valid_for_get_attr(name: Symbol) -> bool {
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| match attr.duplicates {
WarnFollowing | ErrorFollowing | ErrorPreceding | FutureWarnFollowing
| FutureWarnPreceding => true,
DuplicatesOk | WarnFollowingWordOnly => false,
})
}
pub static BUILTIN_ATTRIBUTE_MAP: LazyLock<FxHashMap<Symbol, &BuiltinAttribute>> =
LazyLock::new(|| {
let mut map = FxHashMap::default();
+4 -3
View File
@@ -129,9 +129,10 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option<NonZero<u
pub use accepted::ACCEPTED_LANG_FEATURES;
pub use builtin_attrs::{
AttrSuggestionStyle, AttributeGate, AttributeSafety, AttributeTemplate, BUILTIN_ATTRIBUTE_MAP,
BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg, find_gated_cfg, is_builtin_attr_name,
is_stable_diagnostic_attribute,
AttrSuggestionStyle, AttributeDuplicates, AttributeGate, AttributeSafety, AttributeTemplate,
AttributeType, BUILTIN_ATTRIBUTE_MAP, BUILTIN_ATTRIBUTES, BuiltinAttribute, GatedCfg,
encode_cross_crate, find_gated_cfg, is_builtin_attr_name, is_stable_diagnostic_attribute,
is_valid_for_get_attr,
};
pub use removed::REMOVED_LANG_FEATURES;
pub use unstable::{
@@ -864,6 +864,10 @@ fn analyze_attr(attr: &hir::Attribute, state: &mut AnalyzeAttrState<'_>) -> bool
&& p.encode_cross_crate() == EncodeCrossCrate::No
{
// Attributes not marked encode-cross-crate don't need to be encoded for downstream crates.
} else if let Some(name) = attr.name()
&& !rustc_feature::encode_cross_crate(name)
{
// Attributes not marked encode-cross-crate don't need to be encoded for downstream crates.
} else if let hir::Attribute::Parsed(AttributeKind::DocComment { .. }) = attr {
// We keep all doc comments reachable to rustdoc because they might be "imported" into
// downstream crates if they use `#[doc(inline)]` to copy an item's documentation into
+7 -2
View File
@@ -1725,8 +1725,13 @@ pub fn get_attrs_by_path(
#[deprecated = "Though there are valid usecases for this method, especially when your attribute is not a parsed attribute, usually you want to call rustc_hir::find_attr! instead."]
pub fn get_attr(self, did: impl Into<DefId>, attr: Symbol) -> Option<&'tcx hir::Attribute> {
#[allow(deprecated)]
self.get_attrs(did, attr).next()
if cfg!(debug_assertions) && !rustc_feature::is_valid_for_get_attr(attr) {
let did: DefId = did.into();
bug!("get_attr: unexpected called with DefId `{:?}`, attr `{:?}`", did, attr);
} else {
#[allow(deprecated)]
self.get_attrs(did, attr).next()
}
}
/// Determines whether an item is annotated with an attribute.
+123 -1
View File
@@ -6,15 +6,17 @@
//! item.
use std::cell::Cell;
use std::collections::hash_map::Entry;
use std::slice;
use rustc_abi::ExternAbi;
use rustc_ast::ast;
use rustc_attr_parsing::{AttributeParser, Late};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::thin_vec::ThinVec;
use rustc_data_structures::unord::UnordMap;
use rustc_errors::{DiagCtxtHandle, IntoDiagArg, MultiSpan, msg};
use rustc_feature::BUILTIN_ATTRIBUTE_MAP;
use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute};
use rustc_hir::attrs::diagnostic::Directive;
use rustc_hir::attrs::{
AttributeKind, CrateType, DocAttribute, DocInline, EiiDecl, EiiImpl, EiiImplResolution,
@@ -135,6 +137,7 @@ fn check_attributes(
target: Target,
item: Option<ItemLike<'_>>,
) {
let mut seen = FxHashMap::default();
let attrs = self.tcx.hir_attrs(hir_id);
for attr in attrs {
match attr {
@@ -401,6 +404,64 @@ fn check_attributes(
}
}
if hir_id != CRATE_HIR_ID {
match attr {
Attribute::Parsed(_) => { /* Already validated. */ }
Attribute::Unparsed(attr) => {
// FIXME(jdonszelmann): remove once all crate-level attrs are parsed and caught by
// the above
if let Some(BuiltinAttribute { type_: AttributeType::CrateLevel, .. }) =
attr.path
.segments
.first()
.and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name))
{
match attr.style {
ast::AttrStyle::Outer => {
let attr_span = attr.span;
let bang_position = self
.tcx
.sess
.source_map()
.span_until_char(attr_span, '[')
.shrink_to_hi();
self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
errors::OuterCrateLevelAttr {
suggestion: errors::OuterCrateLevelAttrSuggestion {
bang_position,
},
},
)
}
ast::AttrStyle::Inner => self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
errors::InnerCrateLevelAttr,
),
}
}
}
}
}
if let Attribute::Unparsed(unparsed_attr) = attr
&& let Some(BuiltinAttribute { duplicates, .. }) =
attr.name().and_then(|name| BUILTIN_ATTRIBUTE_MAP.get(&name))
{
check_duplicates(
self.tcx,
unparsed_attr.span,
attr,
hir_id,
*duplicates,
&mut seen,
);
}
self.check_unused_attribute(hir_id, attr)
}
@@ -1933,6 +1994,67 @@ pub(crate) fn provide(providers: &mut Providers) {
*providers = Providers { check_mod_attrs, ..*providers };
}
// FIXME(jdonszelmann): remove, check during parsing
fn check_duplicates(
tcx: TyCtxt<'_>,
attr_span: Span,
attr: &Attribute,
hir_id: HirId,
duplicates: AttributeDuplicates,
seen: &mut FxHashMap<Symbol, Span>,
) {
use AttributeDuplicates::*;
if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
return;
}
let attr_name = attr.name().unwrap();
match duplicates {
DuplicatesOk => {}
WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
match seen.entry(attr_name) {
Entry::Occupied(mut entry) => {
let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
let to_remove = entry.insert(attr_span);
(to_remove, attr_span)
} else {
(attr_span, *entry.get())
};
tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES,
hir_id,
this,
errors::UnusedDuplicate {
this,
other,
warning: matches!(
duplicates,
FutureWarnFollowing | FutureWarnPreceding
),
},
);
}
Entry::Vacant(entry) => {
entry.insert(attr_span);
}
}
}
ErrorFollowing | ErrorPreceding => match seen.entry(attr_name) {
Entry::Occupied(mut entry) => {
let (this, other) = if matches!(duplicates, ErrorPreceding) {
let to_remove = entry.insert(attr_span);
(to_remove, attr_span)
} else {
(attr_span, *entry.get())
};
tcx.dcx().emit_err(errors::UnusedMultiple { this, other, name: attr_name });
}
Entry::Vacant(entry) => {
entry.insert(attr_span);
}
},
}
}
fn doc_fake_variadic_is_allowed_self_ty(self_ty: &hir::Ty<'_>) -> bool {
matches!(&self_ty.kind, hir::TyKind::Tup([_]))
|| if let hir::TyKind::FnPtr(fn_ptr_ty) = &self_ty.kind {
+24
View File
@@ -326,6 +326,30 @@ pub(crate) struct InvalidMayDangle {
pub attr_span: Span,
}
#[derive(Diagnostic)]
#[diag("unused attribute")]
pub(crate) struct UnusedDuplicate {
#[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
pub this: Span,
#[note("attribute also specified here")]
pub other: Span,
#[warning(
"this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!"
)]
pub warning: bool,
}
#[derive(Diagnostic)]
#[diag("multiple `{$name}` attributes")]
pub(crate) struct UnusedMultiple {
#[primary_span]
#[suggestion("remove this attribute", code = "", applicability = "machine-applicable")]
pub this: Span,
#[note("attribute also specified here")]
pub other: Span,
pub name: Symbol,
}
#[derive(Diagnostic)]
#[diag("this `#[deprecated]` annotation has no effect")]
pub(crate) struct DeprecatedAnnotationHasNoEffect {