Rollup merge of #139615 - nnethercote:rm-name_or_empty, r=jdonszelmann

Remove `name_or_empty`

Another step towards #137978.

r? ``@jdonszelmann``
This commit is contained in:
Matthias Krüger 2025-04-18 05:16:29 +02:00 committed by GitHub
commit 540fb228af
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
42 changed files with 309 additions and 226 deletions

View file

@ -305,8 +305,8 @@ impl MetaItem {
if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None } if let [PathSegment { ident, .. }] = self.path.segments[..] { Some(ident) } else { None }
} }
pub fn name_or_empty(&self) -> Symbol { pub fn name(&self) -> Option<Symbol> {
self.ident().unwrap_or_else(Ident::empty).name self.ident().map(|ident| ident.name)
} }
pub fn has_name(&self, name: Symbol) -> bool { pub fn has_name(&self, name: Symbol) -> bool {
@ -511,13 +511,14 @@ impl MetaItemInner {
} }
} }
/// For a single-segment meta item, returns its name; otherwise, returns `None`. /// For a single-segment meta item, returns its identifier; otherwise, returns `None`.
pub fn ident(&self) -> Option<Ident> { pub fn ident(&self) -> Option<Ident> {
self.meta_item().and_then(|meta_item| meta_item.ident()) self.meta_item().and_then(|meta_item| meta_item.ident())
} }
pub fn name_or_empty(&self) -> Symbol { /// For a single-segment meta item, returns its name; otherwise, returns `None`.
self.ident().unwrap_or_else(Ident::empty).name pub fn name(&self) -> Option<Symbol> {
self.ident().map(|ident| ident.name)
} }
/// Returns `true` if this list item is a MetaItem with a name of `name`. /// Returns `true` if this list item is a MetaItem with a name of `name`.
@ -738,9 +739,9 @@ pub trait AttributeExt: Debug {
fn id(&self) -> AttrId; fn id(&self) -> AttrId;
/// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`), /// For a single-segment attribute (i.e., `#[attr]` and not `#[path::atrr]`),
/// return the name of the attribute, else return the empty identifier. /// return the name of the attribute; otherwise, returns `None`.
fn name_or_empty(&self) -> Symbol { fn name(&self) -> Option<Symbol> {
self.ident().unwrap_or_else(Ident::empty).name self.ident().map(|ident| ident.name)
} }
/// Get the meta item list, `#[attr(meta item list)]` /// Get the meta item list, `#[attr(meta item list)]`
@ -752,7 +753,7 @@ pub trait AttributeExt: Debug {
/// Gets the span of the value literal, as string, when using `#[attr = value]` /// Gets the span of the value literal, as string, when using `#[attr = value]`
fn value_span(&self) -> Option<Span>; fn value_span(&self) -> Option<Span>;
/// For a single-segment attribute, returns its name; otherwise, returns `None`. /// For a single-segment attribute, returns its ident; otherwise, returns `None`.
fn ident(&self) -> Option<Ident>; fn ident(&self) -> Option<Ident>;
/// Checks whether the path of this attribute matches the name. /// Checks whether the path of this attribute matches the name.
@ -770,6 +771,11 @@ pub trait AttributeExt: Debug {
self.ident().map(|x| x.name == name).unwrap_or(false) self.ident().map(|x| x.name == name).unwrap_or(false)
} }
#[inline]
fn has_any_name(&self, names: &[Symbol]) -> bool {
names.iter().any(|&name| self.has_name(name))
}
/// get the span of the entire attribute /// get the span of the entire attribute
fn span(&self) -> Span; fn span(&self) -> Span;
@ -813,8 +819,8 @@ impl Attribute {
AttributeExt::id(self) AttributeExt::id(self)
} }
pub fn name_or_empty(&self) -> Symbol { pub fn name(&self) -> Option<Symbol> {
AttributeExt::name_or_empty(self) AttributeExt::name(self)
} }
pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> { pub fn meta_item_list(&self) -> Option<ThinVec<MetaItemInner>> {
@ -846,6 +852,11 @@ impl Attribute {
AttributeExt::has_name(self, name) AttributeExt::has_name(self, name)
} }
#[inline]
pub fn has_any_name(&self, names: &[Symbol]) -> bool {
AttributeExt::has_any_name(self, names)
}
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
AttributeExt::span(self) AttributeExt::span(self)
} }

View file

@ -1310,7 +1310,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
// create a fake body so that the entire rest of the compiler doesn't have to deal with // create a fake body so that the entire rest of the compiler doesn't have to deal with
// this as a special case. // this as a special case.
return self.lower_fn_body(decl, contract, |this| { return self.lower_fn_body(decl, contract, |this| {
if attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic) { if attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic)) {
let span = this.lower_span(span); let span = this.lower_span(span);
let empty_block = hir::Block { let empty_block = hir::Block {
hir_id: this.next_id(), hir_id: this.next_id(),

View file

@ -347,7 +347,7 @@ impl<'a> AstValidator<'a> {
sym::forbid, sym::forbid,
sym::warn, sym::warn,
]; ];
!arr.contains(&attr.name_or_empty()) && rustc_attr_parsing::is_builtin_attr(*attr) !attr.has_any_name(&arr) && rustc_attr_parsing::is_builtin_attr(*attr)
}) })
.for_each(|attr| { .for_each(|attr| {
if attr.is_doc_comment() { if attr.is_doc_comment() {
@ -947,8 +947,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident); self.visit_attrs_vis_ident(&item.attrs, &item.vis, ident);
self.check_defaultness(item.span, *defaultness); self.check_defaultness(item.span, *defaultness);
let is_intrinsic = let is_intrinsic = item.attrs.iter().any(|a| a.has_name(sym::rustc_intrinsic));
item.attrs.iter().any(|a| a.name_or_empty() == sym::rustc_intrinsic);
if body.is_none() && !is_intrinsic { if body.is_none() && !is_intrinsic {
self.dcx().emit_err(errors::FnWithoutBody { self.dcx().emit_err(errors::FnWithoutBody {
span: item.span, span: item.span,

View file

@ -102,7 +102,7 @@ pub fn eval_condition(
}; };
match &cfg.kind { match &cfg.kind {
MetaItemKind::List(mis) if cfg.name_or_empty() == sym::version => { MetaItemKind::List(mis) if cfg.has_name(sym::version) => {
try_gate_cfg(sym::version, cfg.span, sess, features); try_gate_cfg(sym::version, cfg.span, sess, features);
let (min_version, span) = match &mis[..] { let (min_version, span) = match &mis[..] {
[MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => { [MetaItemInner::Lit(MetaItemLit { kind: LitKind::Str(sym, ..), span, .. })] => {
@ -149,18 +149,18 @@ pub fn eval_condition(
// The unwraps below may look dangerous, but we've already asserted // The unwraps below may look dangerous, but we've already asserted
// that they won't fail with the loop above. // that they won't fail with the loop above.
match cfg.name_or_empty() { match cfg.name() {
sym::any => mis Some(sym::any) => mis
.iter() .iter()
// We don't use any() here, because we want to evaluate all cfg condition // We don't use any() here, because we want to evaluate all cfg condition
// as eval_condition can (and does) extra checks // as eval_condition can (and does) extra checks
.fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)), .fold(false, |res, mi| res | eval_condition(mi, sess, features, eval)),
sym::all => mis Some(sym::all) => mis
.iter() .iter()
// We don't use all() here, because we want to evaluate all cfg condition // We don't use all() here, because we want to evaluate all cfg condition
// as eval_condition can (and does) extra checks // as eval_condition can (and does) extra checks
.fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)), .fold(true, |res, mi| res & eval_condition(mi, sess, features, eval)),
sym::not => { Some(sym::not) => {
let [mi] = mis.as_slice() else { let [mi] = mis.as_slice() else {
dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span }); dcx.emit_err(session_diagnostics::ExpectedOneCfgPattern { span: cfg.span });
return false; return false;
@ -168,7 +168,7 @@ pub fn eval_condition(
!eval_condition(mi, sess, features, eval) !eval_condition(mi, sess, features, eval)
} }
sym::target => { Some(sym::target) => {
if let Some(features) = features if let Some(features) = features
&& !features.cfg_target_compact() && !features.cfg_target_compact()
{ {

View file

@ -222,7 +222,7 @@ impl<'sess> AttributeParser<'sess> {
// if we're only looking for a single attribute, // if we're only looking for a single attribute,
// skip all the ones we don't care about // skip all the ones we don't care about
if let Some(expected) = self.parse_only { if let Some(expected) = self.parse_only {
if attr.name_or_empty() != expected { if !attr.has_name(expected) {
continue; continue;
} }
} }
@ -232,7 +232,7 @@ impl<'sess> AttributeParser<'sess> {
// that's expanded right? But no, sometimes, when parsing attributes on macros, // that's expanded right? But no, sometimes, when parsing attributes on macros,
// we already use the lowering logic and these are still there. So, when `omit_doc` // we already use the lowering logic and these are still there. So, when `omit_doc`
// is set we *also* want to ignore these // is set we *also* want to ignore these
if omit_doc == OmitDoc::Skip && attr.name_or_empty() == sym::doc { if omit_doc == OmitDoc::Skip && attr.has_name(sym::doc) {
continue; continue;
} }
@ -250,7 +250,7 @@ impl<'sess> AttributeParser<'sess> {
})) }))
} }
// // FIXME: make doc attributes go through a proper attribute parser // // FIXME: make doc attributes go through a proper attribute parser
// ast::AttrKind::Normal(n) if n.name_or_empty() == sym::doc => { // ast::AttrKind::Normal(n) if n.has_name(sym::doc) => {
// let p = GenericMetaItemParser::from_attr(&n, self.dcx()); // let p = GenericMetaItemParser::from_attr(&n, self.dcx());
// //
// attributes.push(Attribute::Parsed(AttributeKind::DocComment { // attributes.push(Attribute::Parsed(AttributeKind::DocComment {

View file

@ -527,15 +527,14 @@ impl<'a> TraitDef<'a> {
item.attrs item.attrs
.iter() .iter()
.filter(|a| { .filter(|a| {
[ a.has_any_name(&[
sym::allow, sym::allow,
sym::warn, sym::warn,
sym::deny, sym::deny,
sym::forbid, sym::forbid,
sym::stable, sym::stable,
sym::unstable, sym::unstable,
] ])
.contains(&a.name_or_empty())
}) })
.cloned(), .cloned(),
); );

View file

@ -346,20 +346,26 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
no_sanitize_span = Some(attr.span()); no_sanitize_span = Some(attr.span());
if let Some(list) = attr.meta_item_list() { if let Some(list) = attr.meta_item_list() {
for item in list.iter() { for item in list.iter() {
match item.name_or_empty() { match item.name() {
sym::address => { Some(sym::address) => {
codegen_fn_attrs.no_sanitize |= codegen_fn_attrs.no_sanitize |=
SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS
} }
sym::cfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI, Some(sym::cfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::CFI,
sym::kcfi => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI, Some(sym::kcfi) => codegen_fn_attrs.no_sanitize |= SanitizerSet::KCFI,
sym::memory => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY, Some(sym::memory) => {
sym::memtag => codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG, codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMORY
sym::shadow_call_stack => { }
Some(sym::memtag) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::MEMTAG
}
Some(sym::shadow_call_stack) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK codegen_fn_attrs.no_sanitize |= SanitizerSet::SHADOWCALLSTACK
} }
sym::thread => codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD, Some(sym::thread) => {
sym::hwaddress => { codegen_fn_attrs.no_sanitize |= SanitizerSet::THREAD
}
Some(sym::hwaddress) => {
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS
} }
_ => { _ => {
@ -420,9 +426,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
continue; continue;
}; };
let attrib_to_write = match meta_item.name_or_empty() { let attrib_to_write = match meta_item.name() {
sym::prefix_nops => &mut prefix, Some(sym::prefix_nops) => &mut prefix,
sym::entry_nops => &mut entry, Some(sym::entry_nops) => &mut entry,
_ => { _ => {
tcx.dcx().emit_err(errors::UnexpectedParameterName { tcx.dcx().emit_err(errors::UnexpectedParameterName {
span: item.span(), span: item.span(),
@ -786,8 +792,7 @@ impl<'a> MixedExportNameAndNoMangleState<'a> {
fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> { fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
let attrs = tcx.get_attrs(id, sym::rustc_autodiff); let attrs = tcx.get_attrs(id, sym::rustc_autodiff);
let attrs = let attrs = attrs.filter(|attr| attr.has_name(sym::rustc_autodiff)).collect::<Vec<_>>();
attrs.filter(|attr| attr.name_or_empty() == sym::rustc_autodiff).collect::<Vec<_>>();
// check for exactly one autodiff attribute on placeholder functions. // check for exactly one autodiff attribute on placeholder functions.
// There should only be one, since we generate a new placeholder per ad macro. // There should only be one, since we generate a new placeholder per ad macro.

View file

@ -824,10 +824,10 @@ impl SyntaxExtension {
return Err(item.span); return Err(item.span);
} }
match item.name_or_empty() { match item.name() {
sym::no => Ok(CollapseMacroDebuginfo::No), Some(sym::no) => Ok(CollapseMacroDebuginfo::No),
sym::external => Ok(CollapseMacroDebuginfo::External), Some(sym::external) => Ok(CollapseMacroDebuginfo::External),
sym::yes => Ok(CollapseMacroDebuginfo::Yes), Some(sym::yes) => Ok(CollapseMacroDebuginfo::Yes),
_ => Err(item.path.span), _ => Err(item.path.span),
} }
} }

View file

@ -2053,8 +2053,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
) -> Node::OutputTy { ) -> Node::OutputTy {
loop { loop {
return match self.take_first_attr(&mut node) { return match self.take_first_attr(&mut node) {
Some((attr, pos, derives)) => match attr.name_or_empty() { Some((attr, pos, derives)) => match attr.name() {
sym::cfg => { Some(sym::cfg) => {
let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos); let (res, meta_item) = self.expand_cfg_true(&mut node, attr, pos);
if res { if res {
continue; continue;
@ -2071,7 +2071,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
} }
Default::default() Default::default()
} }
sym::cfg_attr => { Some(sym::cfg_attr) => {
self.expand_cfg_attr(&mut node, &attr, pos); self.expand_cfg_attr(&mut node, &attr, pos);
continue; continue;
} }
@ -2144,8 +2144,8 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
) { ) {
loop { loop {
return match self.take_first_attr(node) { return match self.take_first_attr(node) {
Some((attr, pos, derives)) => match attr.name_or_empty() { Some((attr, pos, derives)) => match attr.name() {
sym::cfg => { Some(sym::cfg) => {
let span = attr.span; let span = attr.span;
if self.expand_cfg_true(node, attr, pos).0 { if self.expand_cfg_true(node, attr, pos).0 {
continue; continue;
@ -2154,7 +2154,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
node.expand_cfg_false(self, pos, span); node.expand_cfg_false(self, pos, span);
continue; continue;
} }
sym::cfg_attr => { Some(sym::cfg_attr) => {
self.expand_cfg_attr(node, &attr, pos); self.expand_cfg_attr(node, &attr, pos);
continue; continue;
} }

View file

@ -1237,7 +1237,7 @@ impl AttributeExt for Attribute {
Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => { Attribute::Parsed(AttributeKind::DocComment { kind, comment, .. }) => {
Some((*comment, *kind)) Some((*comment, *kind))
} }
Attribute::Unparsed(_) if self.name_or_empty() == sym::doc => { Attribute::Unparsed(_) if self.has_name(sym::doc) => {
self.value_str().map(|s| (s, CommentKind::Line)) self.value_str().map(|s| (s, CommentKind::Line))
} }
_ => None, _ => None,
@ -1262,8 +1262,8 @@ impl Attribute {
} }
#[inline] #[inline]
pub fn name_or_empty(&self) -> Symbol { pub fn name(&self) -> Option<Symbol> {
AttributeExt::name_or_empty(self) AttributeExt::name(self)
} }
#[inline] #[inline]
@ -1301,6 +1301,11 @@ impl Attribute {
AttributeExt::has_name(self, name) AttributeExt::has_name(self, name)
} }
#[inline]
pub fn has_any_name(&self, names: &[Symbol]) -> bool {
AttributeExt::has_any_name(self, names)
}
#[inline] #[inline]
pub fn span(&self) -> Span { pub fn span(&self) -> Span {
AttributeExt::span(self) AttributeExt::span(self)

View file

@ -488,7 +488,7 @@ fn parse_never_type_options_attr(
item.span(), item.span(),
format!( format!(
"unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)", "unknown or duplicate never type option: `{}` (supported: `fallback`, `diverging_block_default`)",
item.name_or_empty() item.name().unwrap()
), ),
); );
} }

View file

@ -2334,8 +2334,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id); let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id);
let attrs = self.fcx.tcx.hir_attrs(hir_id); let attrs = self.fcx.tcx.hir_attrs(hir_id);
for attr in attrs { for attr in attrs {
if sym::doc == attr.name_or_empty() { if attr.has_name(sym::doc) {
} else if sym::rustc_confusables == attr.name_or_empty() { // do nothing
} else if attr.has_name(sym::rustc_confusables) {
let Some(confusables) = attr.meta_item_list() else { let Some(confusables) = attr.meta_item_list() else {
continue; continue;
}; };
@ -2355,7 +2356,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
continue; continue;
}; };
for v in values { for v in values {
if v.name_or_empty() != sym::alias { if !v.has_name(sym::alias) {
continue; continue;
} }
if let Some(nested) = v.meta_item_list() { if let Some(nested) = v.meta_item_list() {

View file

@ -93,7 +93,7 @@ incremental_undefined_clean_dirty_assertions =
incremental_undefined_clean_dirty_assertions_item = incremental_undefined_clean_dirty_assertions_item =
clean/dirty auto-assertions not yet defined for Node::Item.node={$kind} clean/dirty auto-assertions not yet defined for Node::Item.node={$kind}
incremental_unknown_item = unknown item `{$name}` incremental_unknown_rustc_clean_argument = unknown `rustc_clean` argument
incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name} incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}

View file

@ -107,11 +107,10 @@ pub(crate) struct NotLoaded<'a> {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(incremental_unknown_item)] #[diag(incremental_unknown_rustc_clean_argument)]
pub(crate) struct UnknownItem { pub(crate) struct UnknownRustcCleanArgument {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
pub name: Symbol,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]

View file

@ -405,8 +405,7 @@ fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool {
debug!("check_config: searching for cfg {:?}", value); debug!("check_config: searching for cfg {:?}", value);
cfg = Some(config.contains(&(value, None))); cfg = Some(config.contains(&(value, None)));
} else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) { } else if !(item.has_name(EXCEPT) || item.has_name(LOADED_FROM_DISK)) {
tcx.dcx() tcx.dcx().emit_err(errors::UnknownRustcCleanArgument { span: item.span() });
.emit_err(errors::UnknownItem { span: attr.span(), name: item.name_or_empty() });
} }
} }

View file

@ -249,7 +249,7 @@ impl Level {
/// Converts an `Attribute` to a level. /// Converts an `Attribute` to a level.
pub fn from_attr(attr: &impl AttributeExt) -> Option<(Self, Option<LintExpectationId>)> { pub fn from_attr(attr: &impl AttributeExt) -> Option<(Self, Option<LintExpectationId>)> {
Self::from_symbol(attr.name_or_empty(), || Some(attr.id())) attr.name().and_then(|name| Self::from_symbol(name, || Some(attr.id())))
} }
/// Converts a `Symbol` to a level. /// Converts a `Symbol` to a level.

View file

@ -226,8 +226,8 @@ impl<'tcx> Collector<'tcx> {
let mut wasm_import_module = None; let mut wasm_import_module = None;
let mut import_name_type = None; let mut import_name_type = None;
for item in items.iter() { for item in items.iter() {
match item.name_or_empty() { match item.name() {
sym::name => { Some(sym::name) => {
if name.is_some() { if name.is_some() {
sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() }); sess.dcx().emit_err(errors::MultipleNamesInLink { span: item.span() });
continue; continue;
@ -242,7 +242,7 @@ impl<'tcx> Collector<'tcx> {
} }
name = Some((link_name, span)); name = Some((link_name, span));
} }
sym::kind => { Some(sym::kind) => {
if kind.is_some() { if kind.is_some() {
sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() }); sess.dcx().emit_err(errors::MultipleKindsInLink { span: item.span() });
continue; continue;
@ -304,7 +304,7 @@ impl<'tcx> Collector<'tcx> {
}; };
kind = Some(link_kind); kind = Some(link_kind);
} }
sym::modifiers => { Some(sym::modifiers) => {
if modifiers.is_some() { if modifiers.is_some() {
sess.dcx() sess.dcx()
.emit_err(errors::MultipleLinkModifiers { span: item.span() }); .emit_err(errors::MultipleLinkModifiers { span: item.span() });
@ -316,7 +316,7 @@ impl<'tcx> Collector<'tcx> {
}; };
modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap())); modifiers = Some((link_modifiers, item.name_value_literal_span().unwrap()));
} }
sym::cfg => { Some(sym::cfg) => {
if cfg.is_some() { if cfg.is_some() {
sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() }); sess.dcx().emit_err(errors::MultipleCfgs { span: item.span() });
continue; continue;
@ -346,7 +346,7 @@ impl<'tcx> Collector<'tcx> {
} }
cfg = Some(link_cfg.clone()); cfg = Some(link_cfg.clone());
} }
sym::wasm_import_module => { Some(sym::wasm_import_module) => {
if wasm_import_module.is_some() { if wasm_import_module.is_some() {
sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() }); sess.dcx().emit_err(errors::MultipleWasmImport { span: item.span() });
continue; continue;
@ -357,7 +357,7 @@ impl<'tcx> Collector<'tcx> {
}; };
wasm_import_module = Some((link_wasm_import_module, item.span())); wasm_import_module = Some((link_wasm_import_module, item.span()));
} }
sym::import_name_type => { Some(sym::import_name_type) => {
if import_name_type.is_some() { if import_name_type.is_some() {
sess.dcx() sess.dcx()
.emit_err(errors::MultipleImportNameType { span: item.span() }); .emit_err(errors::MultipleImportNameType { span: item.span() });

View file

@ -821,7 +821,9 @@ struct AnalyzeAttrState<'a> {
#[inline] #[inline]
fn analyze_attr(attr: &impl AttributeExt, state: &mut AnalyzeAttrState<'_>) -> bool { fn analyze_attr(attr: &impl AttributeExt, state: &mut AnalyzeAttrState<'_>) -> bool {
let mut should_encode = false; let mut should_encode = false;
if !rustc_feature::encode_cross_crate(attr.name_or_empty()) { 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. // Attributes not marked encode-cross-crate don't need to be encoded for downstream crates.
} else if attr.doc_str().is_some() { } else if attr.doc_str().is_some() {
// We keep all doc comments reachable to rustdoc because they might be "imported" into // We keep all doc comments reachable to rustdoc because they might be "imported" into

View file

@ -103,8 +103,9 @@ fn parse_attribute(attr: &Attribute) -> MirPhase {
let mut dialect: Option<String> = None; let mut dialect: Option<String> = None;
let mut phase: Option<String> = None; let mut phase: Option<String> = None;
// Not handling errors properly for this internal attribute; will just abort on errors.
for nested in meta_items { for nested in meta_items {
let name = nested.name_or_empty(); let name = nested.name().unwrap();
let value = nested.value_str().unwrap().as_str().to_string(); let value = nested.value_str().unwrap().as_str().to_string();
match name.as_str() { match name.as_str() {
"dialect" => { "dialect" => {

View file

@ -485,7 +485,7 @@ fn construct_fn<'tcx>(
}; };
if let Some(custom_mir_attr) = if let Some(custom_mir_attr) =
tcx.hir_attrs(fn_id).iter().find(|attr| attr.name_or_empty() == sym::custom_mir) tcx.hir_attrs(fn_id).iter().find(|attr| attr.has_name(sym::custom_mir))
{ {
return custom::build_custom_mir( return custom::build_custom_mir(
tcx, tcx,

View file

@ -113,7 +113,7 @@ impl<'tcx> ThirBuildCx<'tcx> {
apply_adjustments: tcx apply_adjustments: tcx
.hir_attrs(hir_id) .hir_attrs(hir_id)
.iter() .iter()
.all(|attr| attr.name_or_empty() != rustc_span::sym::custom_mir), .all(|attr| !attr.has_name(rustc_span::sym::custom_mir)),
} }
} }

View file

@ -109,27 +109,29 @@ impl RustcMirAttrs {
.flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter())); .flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
for attr in rustc_mir_attrs { for attr in rustc_mir_attrs {
let attr_result = if attr.has_name(sym::borrowck_graphviz_postflow) { let attr_result = match attr.name() {
Self::set_field(&mut ret.basename_and_suffix, tcx, &attr, |s| { Some(name @ sym::borrowck_graphviz_postflow) => {
let path = PathBuf::from(s.to_string()); Self::set_field(&mut ret.basename_and_suffix, tcx, name, &attr, |s| {
match path.file_name() { let path = PathBuf::from(s.to_string());
Some(_) => Ok(path), match path.file_name() {
None => { Some(_) => Ok(path),
tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() }); None => {
tcx.dcx().emit_err(PathMustEndInFilename { span: attr.span() });
Err(())
}
}
})
}
Some(name @ sym::borrowck_graphviz_format) => {
Self::set_field(&mut ret.formatter, tcx, name, &attr, |s| match s {
sym::two_phase => Ok(s),
_ => {
tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
Err(()) Err(())
} }
} })
}) }
} else if attr.has_name(sym::borrowck_graphviz_format) { _ => Ok(()),
Self::set_field(&mut ret.formatter, tcx, &attr, |s| match s {
sym::two_phase => Ok(s),
_ => {
tcx.dcx().emit_err(UnknownFormatter { span: attr.span() });
Err(())
}
})
} else {
Ok(())
}; };
result = result.and(attr_result); result = result.and(attr_result);
@ -141,12 +143,12 @@ impl RustcMirAttrs {
fn set_field<T>( fn set_field<T>(
field: &mut Option<T>, field: &mut Option<T>,
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
name: Symbol,
attr: &ast::MetaItemInner, attr: &ast::MetaItemInner,
mapper: impl FnOnce(Symbol) -> Result<T, ()>, mapper: impl FnOnce(Symbol) -> Result<T, ()>,
) -> Result<(), ()> { ) -> Result<(), ()> {
if field.is_some() { if field.is_some() {
tcx.dcx() tcx.dcx().emit_err(DuplicateValuesFor { span: attr.span(), name });
.emit_err(DuplicateValuesFor { span: attr.span(), name: attr.name_or_empty() });
return Err(()); return Err(());
} }
@ -156,7 +158,7 @@ impl RustcMirAttrs {
Ok(()) Ok(())
} else { } else {
tcx.dcx() tcx.dcx()
.emit_err(RequiresAnArgument { span: attr.span(), name: attr.name_or_empty() }); .emit_err(RequiresAnArgument { span: attr.span(), name: attr.name().unwrap() });
Err(()) Err(())
} }
} }

View file

@ -404,7 +404,7 @@ passes_invalid_attr_at_crate_level =
passes_invalid_attr_at_crate_level_item = passes_invalid_attr_at_crate_level_item =
the inner attribute doesn't annotate this {$kind} the inner attribute doesn't annotate this {$kind}
passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument passes_invalid_macro_export_arguments = invalid `#[macro_export]` argument
passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
@ -771,8 +771,8 @@ passes_unreachable_due_to_uninhabited = unreachable {$descr}
.label_orig = any code following this expression is unreachable .label_orig = any code following this expression is unreachable
.note = this expression has type `{$ty}`, which is uninhabited .note = this expression has type `{$ty}`, which is uninhabited
passes_unrecognized_field = passes_unrecognized_argument =
unrecognized field name `{$name}` unrecognized argument
passes_unstable_attr_for_already_stable_feature = passes_unstable_attr_for_already_stable_feature =
can't mark as unstable using an already stable feature can't mark as unstable using an already stable feature

View file

@ -9,7 +9,7 @@ use rustc_span::sym;
use rustc_target::callconv::FnAbi; use rustc_target::callconv::FnAbi;
use super::layout_test::ensure_wf; use super::layout_test::ensure_wf;
use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedField}; use crate::errors::{AbiInvalidAttribute, AbiNe, AbiOf, UnrecognizedArgument};
pub fn test_abi(tcx: TyCtxt<'_>) { pub fn test_abi(tcx: TyCtxt<'_>) {
if !tcx.features().rustc_attrs() { if !tcx.features().rustc_attrs() {
@ -77,8 +77,8 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
// The `..` are the names of fields to dump. // The `..` are the names of fields to dump.
let meta_items = attr.meta_item_list().unwrap_or_default(); let meta_items = attr.meta_item_list().unwrap_or_default();
for meta_item in meta_items { for meta_item in meta_items {
match meta_item.name_or_empty() { match meta_item.name() {
sym::debug => { Some(sym::debug) => {
let fn_name = tcx.item_name(item_def_id.into()); let fn_name = tcx.item_name(item_def_id.into());
tcx.dcx().emit_err(AbiOf { tcx.dcx().emit_err(AbiOf {
span: tcx.def_span(item_def_id), span: tcx.def_span(item_def_id),
@ -88,8 +88,8 @@ fn dump_abi_of_fn_item(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
}); });
} }
name => { _ => {
tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name }); tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() });
} }
} }
} }
@ -118,8 +118,8 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
} }
let meta_items = attr.meta_item_list().unwrap_or_default(); let meta_items = attr.meta_item_list().unwrap_or_default();
for meta_item in meta_items { for meta_item in meta_items {
match meta_item.name_or_empty() { match meta_item.name() {
sym::debug => { Some(sym::debug) => {
let ty::FnPtr(sig_tys, hdr) = ty.kind() else { let ty::FnPtr(sig_tys, hdr) = ty.kind() else {
span_bug!( span_bug!(
meta_item.span(), meta_item.span(),
@ -138,7 +138,7 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
let fn_name = tcx.item_name(item_def_id.into()); let fn_name = tcx.item_name(item_def_id.into());
tcx.dcx().emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) }); tcx.dcx().emit_err(AbiOf { span, fn_name, fn_abi: format!("{:#?}", abi) });
} }
sym::assert_eq => { Some(sym::assert_eq) => {
let ty::Tuple(fields) = ty.kind() else { let ty::Tuple(fields) = ty.kind() else {
span_bug!( span_bug!(
meta_item.span(), meta_item.span(),
@ -188,8 +188,8 @@ fn dump_abi_of_fn_type(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribut
}); });
} }
} }
name => { _ => {
tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name }); tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() });
} }
} }
} }

View file

@ -523,9 +523,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) { fn check_no_sanitize(&self, attr: &Attribute, span: Span, target: Target) {
if let Some(list) = attr.meta_item_list() { if let Some(list) = attr.meta_item_list() {
for item in list.iter() { for item in list.iter() {
let sym = item.name_or_empty(); let sym = item.name();
match sym { match sym {
sym::address | sym::hwaddress => { Some(s @ sym::address | s @ sym::hwaddress) => {
let is_valid = let is_valid =
matches!(target, Target::Fn | Target::Method(..) | Target::Static); matches!(target, Target::Fn | Target::Method(..) | Target::Static);
if !is_valid { if !is_valid {
@ -533,7 +533,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
attr_span: item.span(), attr_span: item.span(),
defn_span: span, defn_span: span,
accepted_kind: "a function or static", accepted_kind: "a function or static",
attr_str: sym.as_str(), attr_str: s.as_str(),
}); });
} }
} }
@ -544,7 +544,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
attr_span: item.span(), attr_span: item.span(),
defn_span: span, defn_span: span,
accepted_kind: "a function", accepted_kind: "a function",
attr_str: sym.as_str(), attr_str: &match sym {
Some(name) => name.to_string(),
None => "...".to_string(),
},
}); });
} }
} }
@ -561,12 +564,15 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
allowed_target: Target, allowed_target: Target,
) { ) {
if target != allowed_target { if target != allowed_target {
let path = attr.path();
let path: Vec<_> = path.iter().map(|s| s.as_str()).collect();
let attr_name = path.join("::");
self.tcx.emit_node_span_lint( self.tcx.emit_node_span_lint(
UNUSED_ATTRIBUTES, UNUSED_ATTRIBUTES,
hir_id, hir_id,
attr.span(), attr.span(),
errors::OnlyHasEffectOn { errors::OnlyHasEffectOn {
attr_name: attr.name_or_empty(), attr_name,
target_name: allowed_target.name().replace(' ', "_"), target_name: allowed_target.name().replace(' ', "_"),
}, },
); );
@ -589,7 +595,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
// * `#[track_caller]` // * `#[track_caller]`
// * `#[test]`, `#[ignore]`, `#[should_panic]` // * `#[test]`, `#[ignore]`, `#[should_panic]`
// //
// NOTE: when making changes to this list, check that `error_codes/E0736.md` remains accurate // NOTE: when making changes to this list, check that `error_codes/E0736.md` remains
// accurate.
const ALLOW_LIST: &[rustc_span::Symbol] = &[ const ALLOW_LIST: &[rustc_span::Symbol] = &[
// conditional compilation // conditional compilation
sym::cfg_trace, sym::cfg_trace,
@ -672,11 +679,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
} }
} }
if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) { if !other_attr.has_any_name(ALLOW_LIST) {
self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute {
span: other_attr.span(), span: other_attr.span(),
naked_span: attr.span(), naked_span: attr.span(),
attr: other_attr.name_or_empty(), attr: other_attr.name().unwrap(),
}); });
return; return;
@ -1150,7 +1157,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
) { ) {
match target { match target {
Target::Use | Target::ExternCrate => { Target::Use | Target::ExternCrate => {
let do_inline = meta.name_or_empty() == sym::inline; let do_inline = meta.has_name(sym::inline);
if let Some((prev_inline, prev_span)) = *specified_inline { if let Some((prev_inline, prev_span)) = *specified_inline {
if do_inline != prev_inline { if do_inline != prev_inline {
let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]); let mut spans = MultiSpan::from_spans(vec![prev_span, meta.span()]);
@ -1260,8 +1267,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) { fn check_test_attr(&self, meta: &MetaItemInner, hir_id: HirId) {
if let Some(metas) = meta.meta_item_list() { if let Some(metas) = meta.meta_item_list() {
for i_meta in metas { for i_meta in metas {
match (i_meta.name_or_empty(), i_meta.meta_item()) { match (i_meta.name(), i_meta.meta_item()) {
(sym::attr | sym::no_crate_inject, _) => {} (Some(sym::attr | sym::no_crate_inject), _) => {}
(_, Some(m)) => { (_, Some(m)) => {
self.tcx.emit_node_span_lint( self.tcx.emit_node_span_lint(
INVALID_DOC_ATTRIBUTES, INVALID_DOC_ATTRIBUTES,
@ -1322,61 +1329,63 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
if let Some(list) = attr.meta_item_list() { if let Some(list) = attr.meta_item_list() {
for meta in &list { for meta in &list {
if let Some(i_meta) = meta.meta_item() { if let Some(i_meta) = meta.meta_item() {
match i_meta.name_or_empty() { match i_meta.name() {
sym::alias => { Some(sym::alias) => {
if self.check_attr_not_crate_level(meta, hir_id, "alias") { if self.check_attr_not_crate_level(meta, hir_id, "alias") {
self.check_doc_alias(meta, hir_id, target, aliases); self.check_doc_alias(meta, hir_id, target, aliases);
} }
} }
sym::keyword => { Some(sym::keyword) => {
if self.check_attr_not_crate_level(meta, hir_id, "keyword") { if self.check_attr_not_crate_level(meta, hir_id, "keyword") {
self.check_doc_keyword(meta, hir_id); self.check_doc_keyword(meta, hir_id);
} }
} }
sym::fake_variadic => { Some(sym::fake_variadic) => {
if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") { if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
self.check_doc_fake_variadic(meta, hir_id); self.check_doc_fake_variadic(meta, hir_id);
} }
} }
sym::search_unbox => { Some(sym::search_unbox) => {
if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") { if self.check_attr_not_crate_level(meta, hir_id, "fake_variadic") {
self.check_doc_search_unbox(meta, hir_id); self.check_doc_search_unbox(meta, hir_id);
} }
} }
sym::test => { Some(sym::test) => {
if self.check_attr_crate_level(attr, meta, hir_id) { if self.check_attr_crate_level(attr, meta, hir_id) {
self.check_test_attr(meta, hir_id); self.check_test_attr(meta, hir_id);
} }
} }
sym::html_favicon_url Some(
| sym::html_logo_url sym::html_favicon_url
| sym::html_playground_url | sym::html_logo_url
| sym::issue_tracker_base_url | sym::html_playground_url
| sym::html_root_url | sym::issue_tracker_base_url
| sym::html_no_source => { | sym::html_root_url
| sym::html_no_source,
) => {
self.check_attr_crate_level(attr, meta, hir_id); self.check_attr_crate_level(attr, meta, hir_id);
} }
sym::cfg_hide => { Some(sym::cfg_hide) => {
if self.check_attr_crate_level(attr, meta, hir_id) { if self.check_attr_crate_level(attr, meta, hir_id) {
self.check_doc_cfg_hide(meta, hir_id); self.check_doc_cfg_hide(meta, hir_id);
} }
} }
sym::inline | sym::no_inline => { Some(sym::inline | sym::no_inline) => {
self.check_doc_inline(attr, meta, hir_id, target, specified_inline) self.check_doc_inline(attr, meta, hir_id, target, specified_inline)
} }
sym::masked => self.check_doc_masked(attr, meta, hir_id, target), Some(sym::masked) => self.check_doc_masked(attr, meta, hir_id, target),
sym::cfg | sym::hidden | sym::notable_trait => {} Some(sym::cfg | sym::hidden | sym::notable_trait) => {}
sym::rust_logo => { Some(sym::rust_logo) => {
if self.check_attr_crate_level(attr, meta, hir_id) if self.check_attr_crate_level(attr, meta, hir_id)
&& !self.tcx.features().rustdoc_internals() && !self.tcx.features().rustdoc_internals()
{ {
@ -2299,7 +2308,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
} }
fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) { fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
let name = attr.name_or_empty(); let name = attr.name().unwrap();
match target { match target {
Target::ExternCrate | Target::Mod => {} Target::ExternCrate | Target::Mod => {}
_ => { _ => {
@ -2331,12 +2340,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
attr.span(), attr.span(),
errors::MacroExport::TooManyItems, errors::MacroExport::TooManyItems,
); );
} else if meta_item_list[0].name_or_empty() != sym::local_inner_macros { } else if !meta_item_list[0].has_name(sym::local_inner_macros) {
self.tcx.emit_node_span_lint( self.tcx.emit_node_span_lint(
INVALID_MACRO_EXPORT_ARGUMENTS, INVALID_MACRO_EXPORT_ARGUMENTS,
hir_id, hir_id,
meta_item_list[0].span(), meta_item_list[0].span(),
errors::MacroExport::UnknownItem { name: meta_item_list[0].name_or_empty() }, errors::MacroExport::InvalidArgument,
); );
} }
} else { } else {
@ -2381,33 +2390,28 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
} }
// Warn on useless empty attributes. // Warn on useless empty attributes.
let note = if (matches!( let note = if attr.has_any_name(&[
attr.name_or_empty(), sym::macro_use,
sym::macro_use sym::allow,
| sym::allow sym::expect,
| sym::expect sym::warn,
| sym::warn sym::deny,
| sym::deny sym::forbid,
| sym::forbid sym::feature,
| sym::feature sym::target_feature,
| sym::target_feature ]) && attr.meta_item_list().is_some_and(|list| list.is_empty())
) && attr.meta_item_list().is_some_and(|list| list.is_empty()))
{ {
errors::UnusedNote::EmptyList { name: attr.name_or_empty() } errors::UnusedNote::EmptyList { name: attr.name().unwrap() }
} else if matches!( } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
attr.name_or_empty(), && let Some(meta) = attr.meta_item_list()
sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
) && let Some(meta) = attr.meta_item_list()
&& let [meta] = meta.as_slice() && let [meta] = meta.as_slice()
&& let Some(item) = meta.meta_item() && let Some(item) = meta.meta_item()
&& let MetaItemKind::NameValue(_) = &item.kind && let MetaItemKind::NameValue(_) = &item.kind
&& item.path == sym::reason && item.path == sym::reason
{ {
errors::UnusedNote::NoLints { name: attr.name_or_empty() } errors::UnusedNote::NoLints { name: attr.name().unwrap() }
} else if matches!( } else if attr.has_any_name(&[sym::allow, sym::warn, sym::deny, sym::forbid, sym::expect])
attr.name_or_empty(), && let Some(meta) = attr.meta_item_list()
sym::allow | sym::warn | sym::deny | sym::forbid | sym::expect
) && let Some(meta) = attr.meta_item_list()
&& meta.iter().any(|meta| { && meta.iter().any(|meta| {
meta.meta_item().map_or(false, |item| item.path == sym::linker_messages) meta.meta_item().map_or(false, |item| item.path == sym::linker_messages)
}) })
@ -2440,7 +2444,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
return; return;
} }
} }
} else if attr.name_or_empty() == sym::default_method_body_is_const { } else if attr.has_name(sym::default_method_body_is_const) {
errors::UnusedNote::DefaultMethodBodyConst errors::UnusedNote::DefaultMethodBodyConst
} else { } else {
return; return;
@ -2897,10 +2901,11 @@ fn check_duplicates(
if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() { if matches!(duplicates, WarnFollowingWordOnly) && !attr.is_word() {
return; return;
} }
let attr_name = attr.name().unwrap();
match duplicates { match duplicates {
DuplicatesOk => {} DuplicatesOk => {}
WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => { WarnFollowing | FutureWarnFollowing | WarnFollowingWordOnly | FutureWarnPreceding => {
match seen.entry(attr.name_or_empty()) { match seen.entry(attr_name) {
Entry::Occupied(mut entry) => { Entry::Occupied(mut entry) => {
let (this, other) = if matches!(duplicates, FutureWarnPreceding) { let (this, other) = if matches!(duplicates, FutureWarnPreceding) {
let to_remove = entry.insert(attr.span()); let to_remove = entry.insert(attr.span());
@ -2927,7 +2932,7 @@ fn check_duplicates(
} }
} }
} }
ErrorFollowing | ErrorPreceding => match seen.entry(attr.name_or_empty()) { ErrorFollowing | ErrorPreceding => match seen.entry(attr_name) {
Entry::Occupied(mut entry) => { Entry::Occupied(mut entry) => {
let (this, other) = if matches!(duplicates, ErrorPreceding) { let (this, other) = if matches!(duplicates, ErrorPreceding) {
let to_remove = entry.insert(attr.span()); let to_remove = entry.insert(attr.span());
@ -2935,11 +2940,7 @@ fn check_duplicates(
} else { } else {
(attr.span(), *entry.get()) (attr.span(), *entry.get())
}; };
tcx.dcx().emit_err(errors::UnusedMultiple { tcx.dcx().emit_err(errors::UnusedMultiple { this, other, name: attr_name });
this,
other,
name: attr.name_or_empty(),
});
} }
Entry::Vacant(entry) => { Entry::Vacant(entry) => {
entry.insert(attr.span()); entry.insert(attr.span());

View file

@ -28,17 +28,17 @@ impl DebuggerVisualizerCollector<'_> {
return; return;
}; };
let (visualizer_type, visualizer_path) = let (visualizer_type, visualizer_path) = match (meta_item.name(), meta_item.value_str())
match (meta_item.name_or_empty(), meta_item.value_str()) { {
(sym::natvis_file, Some(value)) => (DebuggerVisualizerType::Natvis, value), (Some(sym::natvis_file), Some(value)) => (DebuggerVisualizerType::Natvis, value),
(sym::gdb_script_file, Some(value)) => { (Some(sym::gdb_script_file), Some(value)) => {
(DebuggerVisualizerType::GdbPrettyPrinter, value) (DebuggerVisualizerType::GdbPrettyPrinter, value)
} }
(_, _) => { (_, _) => {
self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span }); self.sess.dcx().emit_err(DebugVisualizerInvalid { span: meta_item.span });
return; return;
} }
}; };
let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) { let file = match resolve_path(&self.sess, visualizer_path.as_str(), attr.span) {
Ok(file) => file, Ok(file) => file,

View file

@ -756,7 +756,7 @@ pub(crate) enum MacroExport {
OnDeclMacro, OnDeclMacro,
#[diag(passes_invalid_macro_export_arguments)] #[diag(passes_invalid_macro_export_arguments)]
UnknownItem { name: Symbol }, InvalidArgument,
#[diag(passes_invalid_macro_export_arguments_too_many_items)] #[diag(passes_invalid_macro_export_arguments_too_many_items)]
TooManyItems, TooManyItems,
@ -1045,11 +1045,10 @@ pub(crate) struct AbiInvalidAttribute {
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
#[diag(passes_unrecognized_field)] #[diag(passes_unrecognized_argument)]
pub(crate) struct UnrecognizedField { pub(crate) struct UnrecognizedArgument {
#[primary_span] #[primary_span]
pub span: Span, pub span: Span,
pub name: Symbol,
} }
#[derive(Diagnostic)] #[derive(Diagnostic)]
@ -1433,7 +1432,7 @@ pub(crate) struct UselessAssignment<'a> {
#[derive(LintDiagnostic)] #[derive(LintDiagnostic)]
#[diag(passes_only_has_effect_on)] #[diag(passes_only_has_effect_on)]
pub(crate) struct OnlyHasEffectOn { pub(crate) struct OnlyHasEffectOn {
pub attr_name: Symbol, pub attr_name: String,
pub target_name: String, pub target_name: String,
} }

View file

@ -13,7 +13,7 @@ use rustc_trait_selection::traits;
use crate::errors::{ use crate::errors::{
LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf, LayoutAbi, LayoutAlign, LayoutHomogeneousAggregate, LayoutInvalidAttribute, LayoutOf,
LayoutSize, UnrecognizedField, LayoutSize, UnrecognizedArgument,
}; };
pub fn test_layout(tcx: TyCtxt<'_>) { pub fn test_layout(tcx: TyCtxt<'_>) {
@ -79,28 +79,28 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
// The `..` are the names of fields to dump. // The `..` are the names of fields to dump.
let meta_items = attr.meta_item_list().unwrap_or_default(); let meta_items = attr.meta_item_list().unwrap_or_default();
for meta_item in meta_items { for meta_item in meta_items {
match meta_item.name_or_empty() { match meta_item.name() {
// FIXME: this never was about ABI and now this dump arg is confusing // FIXME: this never was about ABI and now this dump arg is confusing
sym::abi => { Some(sym::abi) => {
tcx.dcx().emit_err(LayoutAbi { tcx.dcx().emit_err(LayoutAbi {
span, span,
abi: format!("{:?}", ty_layout.backend_repr), abi: format!("{:?}", ty_layout.backend_repr),
}); });
} }
sym::align => { Some(sym::align) => {
tcx.dcx().emit_err(LayoutAlign { tcx.dcx().emit_err(LayoutAlign {
span, span,
align: format!("{:?}", ty_layout.align), align: format!("{:?}", ty_layout.align),
}); });
} }
sym::size => { Some(sym::size) => {
tcx.dcx() tcx.dcx()
.emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) }); .emit_err(LayoutSize { span, size: format!("{:?}", ty_layout.size) });
} }
sym::homogeneous_aggregate => { Some(sym::homogeneous_aggregate) => {
tcx.dcx().emit_err(LayoutHomogeneousAggregate { tcx.dcx().emit_err(LayoutHomogeneousAggregate {
span, span,
homogeneous_aggregate: format!( homogeneous_aggregate: format!(
@ -111,15 +111,15 @@ fn dump_layout_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId, attr: &Attribute) {
}); });
} }
sym::debug => { Some(sym::debug) => {
let normalized_ty = tcx.normalize_erasing_regions(typing_env, ty); let normalized_ty = tcx.normalize_erasing_regions(typing_env, ty);
// FIXME: using the `Debug` impl here isn't ideal. // FIXME: using the `Debug` impl here isn't ideal.
let ty_layout = format!("{:#?}", *ty_layout); let ty_layout = format!("{:#?}", *ty_layout);
tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout }); tcx.dcx().emit_err(LayoutOf { span, normalized_ty, ty_layout });
} }
name => { _ => {
tcx.dcx().emit_err(UnrecognizedField { span: meta_item.span(), name }); tcx.dcx().emit_err(UnrecognizedArgument { span: meta_item.span() });
} }
} }
} }

View file

@ -1186,6 +1186,7 @@ symbols! {
instruction_set, instruction_set,
integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below integer_: "integer", // underscore to avoid clashing with the function `sym::integer` below
integral, integral,
internal_features,
into_async_iter_into_iter, into_async_iter_into_iter,
into_future, into_future,
into_iter, into_iter,

View file

@ -788,7 +788,7 @@ impl Item {
} }
_ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)), _ => Some(rustc_hir_pretty::attribute_to_string(&tcx, attr)),
} }
} else if ALLOWED_ATTRIBUTES.contains(&attr.name_or_empty()) { } else if attr.has_any_name(ALLOWED_ATTRIBUTES) {
Some( Some(
rustc_hir_pretty::attribute_to_string(&tcx, attr) rustc_hir_pretty::attribute_to_string(&tcx, attr)
.replace("\\\n", "") .replace("\\\n", "")

View file

@ -412,9 +412,7 @@ pub(crate) fn run_global_ctxt(
// Process all of the crate attributes, extracting plugin metadata along // Process all of the crate attributes, extracting plugin metadata along
// with the passes which we are supposed to run. // with the passes which we are supposed to run.
for attr in krate.module.attrs.lists(sym::doc) { for attr in krate.module.attrs.lists(sym::doc) {
let name = attr.name_or_empty(); if attr.is_word() && attr.has_name(sym::document_private_items) {
if attr.is_word() && name == sym::document_private_items {
ctxt.render_options.document_private = true; ctxt.render_options.document_private = true;
} }
} }

View file

@ -345,7 +345,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) -> bool { fn check_item(item: &ast::Item, info: &mut ParseSourceInfo, crate_name: &Option<&str>) -> bool {
let mut is_extern_crate = false; let mut is_extern_crate = false;
if !info.has_global_allocator if !info.has_global_allocator
&& item.attrs.iter().any(|attr| attr.name_or_empty() == sym::global_allocator) && item.attrs.iter().any(|attr| attr.has_name(sym::global_allocator))
{ {
info.has_global_allocator = true; info.has_global_allocator = true;
} }
@ -377,7 +377,7 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
} }
let mut prev_span_hi = 0; let mut prev_span_hi = 0;
let not_crate_attrs = [sym::forbid, sym::allow, sym::warn, sym::deny, sym::expect]; let not_crate_attrs = &[sym::forbid, sym::allow, sym::warn, sym::deny, sym::expect];
let parsed = parser.parse_item(rustc_parse::parser::ForceCollect::No); let parsed = parser.parse_item(rustc_parse::parser::ForceCollect::No);
let result = match parsed { let result = match parsed {
@ -386,17 +386,13 @@ fn parse_source(source: &str, crate_name: &Option<&str>) -> Result<ParseSourceIn
&& let Some(ref body) = fn_item.body => && let Some(ref body) = fn_item.body =>
{ {
for attr in &item.attrs { for attr in &item.attrs {
let attr_name = attr.name_or_empty(); if attr.style == AttrStyle::Outer || attr.has_any_name(not_crate_attrs) {
if attr.style == AttrStyle::Outer || not_crate_attrs.contains(&attr_name) {
// There is one exception to these attributes: // There is one exception to these attributes:
// `#![allow(internal_features)]`. If this attribute is used, we need to // `#![allow(internal_features)]`. If this attribute is used, we need to
// consider it only as a crate-level attribute. // consider it only as a crate-level attribute.
if attr_name == sym::allow if attr.has_name(sym::allow)
&& let Some(list) = attr.meta_item_list() && let Some(list) = attr.meta_item_list()
&& list.iter().any(|sub_attr| { && list.iter().any(|sub_attr| sub_attr.has_name(sym::internal_features))
sub_attr.name_or_empty().as_str() == "internal_features"
})
{ {
push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi); push_to_s(&mut info.crate_attrs, source, attr.span, &mut prev_span_hi);
} else { } else {

View file

@ -521,23 +521,23 @@ impl<'tcx> FormatRenderer<'tcx> for Context<'tcx> {
// Crawl the crate attributes looking for attributes which control how we're // Crawl the crate attributes looking for attributes which control how we're
// going to emit HTML // going to emit HTML
for attr in krate.module.attrs.lists(sym::doc) { for attr in krate.module.attrs.lists(sym::doc) {
match (attr.name_or_empty(), attr.value_str()) { match (attr.name(), attr.value_str()) {
(sym::html_favicon_url, Some(s)) => { (Some(sym::html_favicon_url), Some(s)) => {
layout.favicon = s.to_string(); layout.favicon = s.to_string();
} }
(sym::html_logo_url, Some(s)) => { (Some(sym::html_logo_url), Some(s)) => {
layout.logo = s.to_string(); layout.logo = s.to_string();
} }
(sym::html_playground_url, Some(s)) => { (Some(sym::html_playground_url), Some(s)) => {
playground = Some(markdown::Playground { playground = Some(markdown::Playground {
crate_name: Some(krate.name(tcx)), crate_name: Some(krate.name(tcx)),
url: s.to_string(), url: s.to_string(),
}); });
} }
(sym::issue_tracker_base_url, Some(s)) => { (Some(sym::issue_tracker_base_url), Some(s)) => {
issue_tracker_base_url = Some(s.to_string()); issue_tracker_base_url = Some(s.to_string());
} }
(sym::html_no_source, None) if attr.is_word() => { (Some(sym::html_no_source), None) if attr.is_word() => {
include_sources = false; include_sources = false;
} }
_ => {} _ => {}

View file

@ -2363,14 +2363,14 @@ pub fn is_no_std_crate(cx: &LateContext<'_>) -> bool {
cx.tcx cx.tcx
.hir_attrs(hir::CRATE_HIR_ID) .hir_attrs(hir::CRATE_HIR_ID)
.iter() .iter()
.any(|attr| attr.name_or_empty() == sym::no_std) .any(|attr| attr.has_name(sym::no_std))
} }
pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool { pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
cx.tcx cx.tcx
.hir_attrs(hir::CRATE_HIR_ID) .hir_attrs(hir::CRATE_HIR_ID)
.iter() .iter()
.any(|attr| attr.name_or_empty() == sym::no_core) .any(|attr| attr.has_name(sym::no_core))
} }
/// Check if parent of a hir node is a trait implementation block. /// Check if parent of a hir node is a trait implementation block.

View file

@ -52,3 +52,6 @@ type TestAbiNeSign = (fn(i32), fn(u32)); //~ ERROR: ABIs are not compatible
#[rustc_abi(assert_eq)] #[rustc_abi(assert_eq)]
type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); //~ ERROR: cannot be known at compilation time type TestAbiEqNonsense = (fn((str, str)), fn((str, str))); //~ ERROR: cannot be known at compilation time
#[rustc_abi("assert_eq")] //~ ERROR unrecognized argument
type Bad = u32;

View file

@ -906,6 +906,12 @@ LL | type TestAbiEqNonsense = (fn((str, str)), fn((str, str)));
= help: the trait `Sized` is not implemented for `str` = help: the trait `Sized` is not implemented for `str`
= note: only the last element of a tuple may have a dynamically sized type = note: only the last element of a tuple may have a dynamically sized type
error: unrecognized argument
--> $DIR/debug.rs:56:13
|
LL | #[rustc_abi("assert_eq")]
| ^^^^^^^^^^^
error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions error: `#[rustc_abi]` can only be applied to function items, type aliases, and associated functions
--> $DIR/debug.rs:29:5 --> $DIR/debug.rs:29:5
| |
@ -1004,6 +1010,6 @@ error: fn_abi_of(assoc_test) = FnAbi {
LL | fn assoc_test(&self) { } LL | fn assoc_test(&self) { }
| ^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^
error: aborting due to 11 previous errors error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0277`. For more information about this error, try `rustc --explain E0277`.

View file

@ -39,13 +39,17 @@
// Notably, `should_panic` is a `AttributeType::Normal` attribute that is checked separately. // Notably, `should_panic` is a `AttributeType::Normal` attribute that is checked separately.
#![deny(unused_attributes)]
struct Foo { struct Foo {
#[should_panic::skip] #[should_panic::skip]
//~^ ERROR failed to resolve //~^ ERROR failed to resolve
//~| ERROR `#[should_panic::skip]` only has an effect on functions
pub field: u8, pub field: u8,
#[should_panic::a::b::c] #[should_panic::a::b::c]
//~^ ERROR failed to resolve //~^ ERROR failed to resolve
//~| ERROR `#[should_panic::a::b::c]` only has an effect on functions
pub field2: u8, pub field2: u8,
} }

View file

@ -1,21 +1,39 @@
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `should_panic` error[E0433]: failed to resolve: use of unresolved module or unlinked crate `should_panic`
--> $DIR/check-builtin-attr-ice.rs:43:7 --> $DIR/check-builtin-attr-ice.rs:45:7
| |
LL | #[should_panic::skip] LL | #[should_panic::skip]
| ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic` | ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic`
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `should_panic` error[E0433]: failed to resolve: use of unresolved module or unlinked crate `should_panic`
--> $DIR/check-builtin-attr-ice.rs:47:7 --> $DIR/check-builtin-attr-ice.rs:50:7
| |
LL | #[should_panic::a::b::c] LL | #[should_panic::a::b::c]
| ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic` | ^^^^^^^^^^^^ use of unresolved module or unlinked crate `should_panic`
error[E0433]: failed to resolve: use of unresolved module or unlinked crate `deny` error[E0433]: failed to resolve: use of unresolved module or unlinked crate `deny`
--> $DIR/check-builtin-attr-ice.rs:55:7 --> $DIR/check-builtin-attr-ice.rs:59:7
| |
LL | #[deny::skip] LL | #[deny::skip]
| ^^^^ use of unresolved module or unlinked crate `deny` | ^^^^ use of unresolved module or unlinked crate `deny`
error: aborting due to 3 previous errors error: `#[should_panic::skip]` only has an effect on functions
--> $DIR/check-builtin-attr-ice.rs:45:5
|
LL | #[should_panic::skip]
| ^^^^^^^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/check-builtin-attr-ice.rs:42:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
error: `#[should_panic::a::b::c]` only has an effect on functions
--> $DIR/check-builtin-attr-ice.rs:50:5
|
LL | #[should_panic::a::b::c]
| ^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 5 previous errors
For more information about this error, try `rustc --explain E0433`. For more information about this error, try `rustc --explain E0433`.

View file

@ -10,11 +10,17 @@ note: the lint level is defined here
LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))] LL | #![cfg_attr(deny, deny(invalid_macro_export_arguments))]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: `not_local_inner_macros` isn't a valid `#[macro_export]` argument error: invalid `#[macro_export]` argument
--> $DIR/invalid_macro_export_argument.rs:13:16 --> $DIR/invalid_macro_export_argument.rs:13:16
| |
LL | #[macro_export(not_local_inner_macros)] LL | #[macro_export(not_local_inner_macros)]
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors error: invalid `#[macro_export]` argument
--> $DIR/invalid_macro_export_argument.rs:33:16
|
LL | #[macro_export("blah")]
| ^^^^^^
error: aborting due to 3 previous errors

View file

@ -11,7 +11,7 @@ macro_rules! a {
} }
#[macro_export(not_local_inner_macros)] #[macro_export(not_local_inner_macros)]
//[deny]~^ ERROR `not_local_inner_macros` isn't a valid `#[macro_export]` argument //[deny]~^ ERROR invalid `#[macro_export]` argument
macro_rules! b { macro_rules! b {
() => () () => ()
} }
@ -30,4 +30,10 @@ macro_rules! e {
() => () () => ()
} }
#[macro_export("blah")]
//[deny]~^ ERROR invalid `#[macro_export]` argument
macro_rules! f {
() => ()
}
fn main() {} fn main() {}

View file

@ -38,3 +38,8 @@ fn valid() {}
#[no_sanitize(address)] #[no_sanitize(address)]
static VALID : i32 = 0; static VALID : i32 = 0;
#[no_sanitize("address")]
//~^ ERROR `#[no_sanitize(...)]` should be applied to a function
//~| ERROR invalid argument for `no_sanitize`
static VALID2 : i32 = 0;

View file

@ -59,5 +59,22 @@ LL | #[no_sanitize(address, memory)]
LL | static INVALID : i32 = 0; LL | static INVALID : i32 = 0;
| ------------------------- not a function | ------------------------- not a function
error: aborting due to 7 previous errors error: `#[no_sanitize(...)]` should be applied to a function
--> $DIR/no-sanitize.rs:42:15
|
LL | #[no_sanitize("address")]
| ^^^^^^^^^
...
LL | static VALID2 : i32 = 0;
| ------------------------ not a function
error: invalid argument for `no_sanitize`
--> $DIR/no-sanitize.rs:42:15
|
LL | #[no_sanitize("address")]
| ^^^^^^^^^
|
= note: expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
error: aborting due to 9 previous errors