Remove Session.used_attrs and move logic to CheckAttrVisitor

Instead of updating global state to mark attributes as used,
we now explicitly emit a warning when an attribute is used in
an unsupported position. As a side effect, we are to emit more
detailed warning messages (instead of just a generic "unused" message).

`Session.check_name` is removed, since its only purpose was to mark
the attribute as used. All of the callers are modified to use
`Attribute.has_name`

Additionally, `AttributeType::AssumedUsed` is removed - an 'assumed
used' attribute is implemented by simply not performing any checks
in `CheckAttrVisitor` for a particular attribute.

We no longer emit unused attribute warnings for the `#[rustc_dummy]`
attribute - it's an internal attribute used for tests, so it doesn't
mark sense to treat it as 'unused'.

With this commit, a large source of global untracked state is removed.
This commit is contained in:
Aaron Hill 2021-07-29 12:00:41 -05:00
parent b6e334d873
commit af46699f81
No known key found for this signature in database
GPG Key ID: B4087E510E98B164
62 changed files with 535 additions and 739 deletions

View File

@ -4115,10 +4115,12 @@ dependencies = [
"rustc_attr", "rustc_attr",
"rustc_data_structures", "rustc_data_structures",
"rustc_errors", "rustc_errors",
"rustc_feature",
"rustc_hir", "rustc_hir",
"rustc_index", "rustc_index",
"rustc_lexer", "rustc_lexer",
"rustc_middle", "rustc_middle",
"rustc_parse",
"rustc_serialize", "rustc_serialize",
"rustc_session", "rustc_session",
"rustc_span", "rustc_span",

View File

@ -2281,7 +2281,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
synthetic: param synthetic: param
.attrs .attrs
.iter() .iter()
.filter(|attr| self.sess.check_name(attr, sym::rustc_synthetic)) .filter(|attr| attr.has_name(sym::rustc_synthetic))
.map(|_| hir::SyntheticTyParamKind::FromAttr) .map(|_| hir::SyntheticTyParamKind::FromAttr)
.next(), .next(),
}; };

View File

@ -268,7 +268,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
gate_feature_fn!(self, has_feature, attr.span, name, descr); gate_feature_fn!(self, has_feature, attr.span, name, descr);
} }
// Check unstable flavors of the `#[doc]` attribute. // Check unstable flavors of the `#[doc]` attribute.
if self.sess.check_name(attr, sym::doc) { if attr.has_name(sym::doc) {
for nested_meta in attr.meta_item_list().unwrap_or_default() { for nested_meta in attr.meta_item_list().unwrap_or_default() {
macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => { macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
$(if nested_meta.has_name(sym::$name) { $(if nested_meta.has_name(sym::$name) {
@ -287,7 +287,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
} }
// Check for unstable modifiers on `#[link(..)]` attribute // Check for unstable modifiers on `#[link(..)]` attribute
if self.sess.check_name(attr, sym::link) { if attr.has_name(sym::link) {
for nested_meta in attr.meta_item_list().unwrap_or_default() { for nested_meta in attr.meta_item_list().unwrap_or_default() {
if nested_meta.has_name(sym::modifiers) { if nested_meta.has_name(sym::modifiers) {
gate_feature_post!( gate_feature_post!(
@ -709,7 +709,7 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
if !sess.opts.unstable_features.is_nightly_build() { if !sess.opts.unstable_features.is_nightly_build() {
let lang_features = &sess.features_untracked().declared_lang_features; let lang_features = &sess.features_untracked().declared_lang_features;
for attr in krate.attrs.iter().filter(|attr| sess.check_name(attr, sym::feature)) { for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) {
let mut err = struct_span_err!( let mut err = struct_span_err!(
sess.parse_sess.span_diagnostic, sess.parse_sess.span_diagnostic,
attr.span, attr.span,

View File

@ -166,8 +166,6 @@ where
continue; // not a stability level continue; // not a stability level
} }
sess.mark_attr_used(attr);
let meta = attr.meta(); let meta = attr.meta();
if attr.has_name(sym::rustc_promotable) { if attr.has_name(sym::rustc_promotable) {
@ -636,8 +634,7 @@ where
let diagnostic = &sess.parse_sess.span_diagnostic; let diagnostic = &sess.parse_sess.span_diagnostic;
'outer: for attr in attrs_iter { 'outer: for attr in attrs_iter {
if !(sess.check_name(attr, sym::deprecated) || sess.check_name(attr, sym::rustc_deprecated)) if !(attr.has_name(sym::deprecated) || attr.has_name(sym::rustc_deprecated)) {
{
continue; continue;
} }
@ -700,17 +697,17 @@ where
continue 'outer; continue 'outer;
} }
} }
sym::note if sess.check_name(attr, sym::deprecated) => { sym::note if attr.has_name(sym::deprecated) => {
if !get(mi, &mut note) { if !get(mi, &mut note) {
continue 'outer; continue 'outer;
} }
} }
sym::reason if sess.check_name(attr, sym::rustc_deprecated) => { sym::reason if attr.has_name(sym::rustc_deprecated) => {
if !get(mi, &mut note) { if !get(mi, &mut note) {
continue 'outer; continue 'outer;
} }
} }
sym::suggestion if sess.check_name(attr, sym::rustc_deprecated) => { sym::suggestion if attr.has_name(sym::rustc_deprecated) => {
if !get(mi, &mut suggestion) { if !get(mi, &mut suggestion) {
continue 'outer; continue 'outer;
} }
@ -721,7 +718,7 @@ where
meta.span(), meta.span(),
AttrError::UnknownMetaItem( AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path), pprust::path_to_string(&mi.path),
if sess.check_name(attr, sym::deprecated) { if attr.has_name(sym::deprecated) {
&["since", "note"] &["since", "note"]
} else { } else {
&["since", "reason", "suggestion"] &["since", "reason", "suggestion"]
@ -747,11 +744,11 @@ where
} }
} }
if suggestion.is_some() && sess.check_name(attr, sym::deprecated) { if suggestion.is_some() && attr.has_name(sym::deprecated) {
unreachable!("only allowed on rustc_deprecated") unreachable!("only allowed on rustc_deprecated")
} }
if sess.check_name(attr, sym::rustc_deprecated) { if attr.has_name(sym::rustc_deprecated) {
if since.is_none() { if since.is_none() {
handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince); handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
continue; continue;
@ -763,9 +760,7 @@ where
} }
} }
sess.mark_attr_used(&attr); let is_since_rustc_version = attr.has_name(sym::rustc_deprecated);
let is_since_rustc_version = sess.check_name(attr, sym::rustc_deprecated);
depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span)); depr = Some((Deprecation { since, note, suggestion, is_since_rustc_version }, attr.span));
} }
@ -816,7 +811,6 @@ pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
let diagnostic = &sess.parse_sess.span_diagnostic; let diagnostic = &sess.parse_sess.span_diagnostic;
if attr.has_name(sym::repr) { if attr.has_name(sym::repr) {
if let Some(items) = attr.meta_item_list() { if let Some(items) = attr.meta_item_list() {
sess.mark_attr_used(attr);
for item in items { for item in items {
let mut recognised = false; let mut recognised = false;
if item.is_word() { if item.is_word() {
@ -1015,14 +1009,13 @@ pub enum TransparencyError {
} }
pub fn find_transparency( pub fn find_transparency(
sess: &Session,
attrs: &[Attribute], attrs: &[Attribute],
macro_rules: bool, macro_rules: bool,
) -> (Transparency, Option<TransparencyError>) { ) -> (Transparency, Option<TransparencyError>) {
let mut transparency = None; let mut transparency = None;
let mut error = None; let mut error = None;
for attr in attrs { for attr in attrs {
if sess.check_name(attr, sym::rustc_macro_transparency) { if attr.has_name(sym::rustc_macro_transparency) {
if let Some((_, old_span)) = transparency { if let Some((_, old_span)) = transparency {
error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span)); error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span));
break; break;

View File

@ -677,8 +677,6 @@ impl<'a> TraitDef<'a> {
let self_type = cx.ty_path(path); let self_type = cx.ty_path(path);
let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived)); let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
// Just mark it now since we know that it'll end up used downstream
cx.sess.mark_attr_used(&attr);
let opt_trait_ref = Some(trait_ref); let opt_trait_ref = Some(trait_ref);
let unused_qual = { let unused_qual = {
let word = rustc_ast::attr::mk_nested_word_item(Ident::new( let word = rustc_ast::attr::mk_nested_word_item(Ident::new(

View File

@ -260,11 +260,11 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
return; return;
} }
if self.sess.check_name(attr, sym::proc_macro_derive) { if attr.has_name(sym::proc_macro_derive) {
self.collect_custom_derive(item, attr); self.collect_custom_derive(item, attr);
} else if self.sess.check_name(attr, sym::proc_macro_attribute) { } else if attr.has_name(sym::proc_macro_attribute) {
self.collect_attr_proc_macro(item); self.collect_attr_proc_macro(item);
} else if self.sess.check_name(attr, sym::proc_macro) { } else if attr.has_name(sym::proc_macro) {
self.collect_bang_proc_macro(item); self.collect_bang_proc_macro(item);
}; };

View File

@ -188,8 +188,7 @@ impl<'a> MutVisitor for EntryPointCleaner<'a> {
let attrs = attrs let attrs = attrs
.into_iter() .into_iter()
.filter(|attr| { .filter(|attr| {
!self.sess.check_name(attr, sym::rustc_main) !attr.has_name(sym::rustc_main) && !attr.has_name(sym::start)
&& !self.sess.check_name(attr, sym::start)
}) })
.chain(iter::once(allow_dead_code)) .chain(iter::once(allow_dead_code))
.collect(); .collect();

View File

@ -5,7 +5,7 @@ use rustc_ast::token::{DelimToken, Token, TokenKind};
use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree}; use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
use rustc_ast::tokenstream::{DelimSpan, Spacing}; use rustc_ast::tokenstream::{DelimSpan, Spacing};
use rustc_ast::tokenstream::{LazyTokenStream, TokenTree}; use rustc_ast::tokenstream::{LazyTokenStream, TokenTree};
use rustc_ast::{self as ast, AstLike, AttrItem, AttrStyle, Attribute, MetaItem}; use rustc_ast::{self as ast, AstLike, AttrStyle, Attribute, MetaItem};
use rustc_attr as attr; use rustc_attr as attr;
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::map_in_place::MapInPlace;
@ -14,7 +14,7 @@ use rustc_feature::{Feature, Features, State as FeatureState};
use rustc_feature::{ use rustc_feature::{
ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES, ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES,
}; };
use rustc_parse::{parse_in, validate_attr}; use rustc_parse::validate_attr;
use rustc_session::parse::feature_err; use rustc_session::parse::feature_err;
use rustc_session::Session; use rustc_session::Session;
use rustc_span::edition::{Edition, ALL_EDITIONS}; use rustc_span::edition::{Edition, ALL_EDITIONS};
@ -75,7 +75,7 @@ fn get_features(
// Process the edition umbrella feature-gates first, to ensure // Process the edition umbrella feature-gates first, to ensure
// `edition_enabled_features` is completed before it's queried. // `edition_enabled_features` is completed before it's queried.
for attr in krate_attrs { for attr in krate_attrs {
if !sess.check_name(attr, sym::feature) { if !attr.has_name(sym::feature) {
continue; continue;
} }
@ -108,7 +108,7 @@ fn get_features(
} }
for attr in krate_attrs { for attr in krate_attrs {
if !sess.check_name(attr, sym::feature) { if !attr.has_name(sym::feature) {
continue; continue;
} }
@ -237,11 +237,6 @@ macro_rules! configure {
}; };
} }
const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
<https://doc.rust-lang.org/reference/conditional-compilation.html\
#the-cfg_attr-attribute>";
impl<'a> StripUnconfigured<'a> { impl<'a> StripUnconfigured<'a> {
pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> { pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node); self.process_cfg_attrs(&mut node);
@ -349,19 +344,17 @@ impl<'a> StripUnconfigured<'a> {
return vec![attr]; return vec![attr];
} }
let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) { let (cfg_predicate, expanded_attrs) =
None => return vec![], match rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) {
Some(r) => r, None => return vec![],
}; Some(r) => r,
};
// Lint on zero attributes in source. // Lint on zero attributes in source.
if expanded_attrs.is_empty() { if expanded_attrs.is_empty() {
return vec![attr]; return vec![attr];
} }
// At this point we know the attribute is considered used.
self.sess.mark_attr_used(&attr);
if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) { if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) {
return vec![]; return vec![];
} }
@ -415,46 +408,10 @@ impl<'a> StripUnconfigured<'a> {
.collect() .collect()
} }
fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
match attr.get_normal_item().args {
ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
let msg = "wrong `cfg_attr` delimiters";
validate_attr::check_meta_bad_delim(&self.sess.parse_sess, dspan, delim, msg);
match parse_in(&self.sess.parse_sess, tts.clone(), "`cfg_attr` input", |p| {
p.parse_cfg_attr()
}) {
Ok(r) => return Some(r),
Err(mut e) => {
e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
.note(CFG_ATTR_NOTE_REF)
.emit();
}
}
}
_ => self.error_malformed_cfg_attr_missing(attr.span),
}
None
}
fn error_malformed_cfg_attr_missing(&self, span: Span) {
self.sess
.parse_sess
.span_diagnostic
.struct_span_err(span, "malformed `cfg_attr` attribute input")
.span_suggestion(
span,
"missing condition and attribute",
CFG_ATTR_GRAMMAR_HELP.to_string(),
Applicability::HasPlaceholders,
)
.note(CFG_ATTR_NOTE_REF)
.emit();
}
/// Determines if a node with the given attributes should be included in this configuration. /// Determines if a node with the given attributes should be included in this configuration.
fn in_cfg(&self, attrs: &[Attribute]) -> bool { fn in_cfg(&self, attrs: &[Attribute]) -> bool {
attrs.iter().all(|attr| { attrs.iter().all(|attr| {
if !is_cfg(self.sess, attr) { if !is_cfg(attr) {
return true; return true;
} }
let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) { let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
@ -500,7 +457,7 @@ impl<'a> StripUnconfigured<'a> {
// //
// N.B., this is intentionally not part of the visit_expr() function // N.B., this is intentionally not part of the visit_expr() function
// in order for filter_map_expr() to be able to avoid this check // in order for filter_map_expr() to be able to avoid this check
if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(self.sess, a)) { if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(*a)) {
let msg = "removing an expression is not supported in this position"; let msg = "removing an expression is not supported in this position";
self.sess.parse_sess.span_diagnostic.span_err(attr.span, msg); self.sess.parse_sess.span_diagnostic.span_err(attr.span, msg);
} }
@ -536,6 +493,6 @@ pub fn parse_cfg<'a>(meta_item: &'a MetaItem, sess: &Session) -> Option<&'a Meta
} }
} }
fn is_cfg(sess: &Session, attr: &Attribute) -> bool { fn is_cfg(attr: &Attribute) -> bool {
sess.check_name(attr, sym::cfg) attr.has_name(sym::cfg)
} }

View File

@ -753,11 +753,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
} }
} }
} }
SyntaxExtensionKind::NonMacroAttr { mark_used } => { SyntaxExtensionKind::NonMacroAttr { mark_used: _ } => {
self.cx.expanded_inert_attrs.mark(&attr); self.cx.expanded_inert_attrs.mark(&attr);
if *mark_used {
self.cx.sess.mark_attr_used(&attr);
}
item.visit_attrs(|attrs| attrs.insert(pos, attr)); item.visit_attrs(|attrs| attrs.insert(pos, attr));
fragment_kind.expect_from_annotatables(iter::once(item)) fragment_kind.expect_from_annotatables(iter::once(item))
} }

View File

@ -535,7 +535,7 @@ pub fn compile_declarative_macro(
valid &= macro_check::check_meta_variables(&sess.parse_sess, def.id, def.span, &lhses, &rhses); valid &= macro_check::check_meta_variables(&sess.parse_sess, def.id, def.span, &lhses, &rhses);
let (transparency, transparency_error) = attr::find_transparency(sess, &def.attrs, macro_rules); let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
match transparency_error { match transparency_error {
Some(TransparencyError::UnknownTransparency(value, span)) => { Some(TransparencyError::UnknownTransparency(value, span)) => {
diag.span_err(span, &format!("unknown macro transparency: `{}`", value)) diag.span_err(span, &format!("unknown macro transparency: `{}`", value))

View File

@ -52,11 +52,6 @@ pub enum AttributeType {
/// by the compiler before the unused_attribute check /// by the compiler before the unused_attribute check
Normal, Normal,
/// Builtin attribute that may not be consumed by the compiler
/// before the unused_attribute check. These attributes
/// will be ignored by the unused_attribute lint
AssumedUsed,
/// Builtin attribute that is only allowed at the crate level /// Builtin attribute that is only allowed at the crate level
CrateLevel, CrateLevel,
} }
@ -186,7 +181,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"), template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
), ),
// FIXME(Centril): This can be used on stable but shouldn't. // FIXME(Centril): This can be used on stable but shouldn't.
ungated!(reexport_test_harness_main, Normal, template!(NameValueStr: "name")), ungated!(reexport_test_harness_main, CrateLevel, template!(NameValueStr: "name")),
// Macros: // Macros:
ungated!(automatically_derived, Normal, template!(Word)), ungated!(automatically_derived, Normal, template!(Word)),
@ -206,7 +201,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(allow, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(forbid, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)), ungated!(deny, Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#)),
ungated!(must_use, AssumedUsed, template!(Word, NameValueStr: "reason")), ungated!(must_use, Normal, template!(Word, NameValueStr: "reason")),
// FIXME(#14407) // FIXME(#14407)
ungated!( ungated!(
deprecated, Normal, deprecated, Normal,
@ -224,16 +219,16 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ABI, linking, symbols, and FFI // ABI, linking, symbols, and FFI
ungated!( ungated!(
link, AssumedUsed, link, Normal,
template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#), template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
), ),
ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")), ungated!(link_name, Normal, template!(NameValueStr: "name")),
ungated!(no_link, AssumedUsed, template!(Word)), ungated!(no_link, Normal, template!(Word)),
ungated!(repr, AssumedUsed, template!(List: "C")), ungated!(repr, Normal, template!(List: "C")),
ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")), ungated!(export_name, Normal, template!(NameValueStr: "name")),
ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")), ungated!(link_section, Normal, template!(NameValueStr: "name")),
ungated!(no_mangle, AssumedUsed, template!(Word)), ungated!(no_mangle, Normal, template!(Word)),
ungated!(used, AssumedUsed, template!(Word)), ungated!(used, Normal, template!(Word)),
// Limits: // Limits:
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")), ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")),
@ -256,37 +251,37 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Modules, prelude, and resolution: // Modules, prelude, and resolution:
ungated!(path, Normal, template!(NameValueStr: "file")), ungated!(path, Normal, template!(NameValueStr: "file")),
ungated!(no_std, CrateLevel, template!(Word)), ungated!(no_std, CrateLevel, template!(Word)),
ungated!(no_implicit_prelude, Normal, template!(Word)), ungated!(no_implicit_prelude, CrateLevel, template!(Word)),
ungated!(non_exhaustive, AssumedUsed, template!(Word)), ungated!(non_exhaustive, Normal, template!(Word)),
// Runtime // Runtime
ungated!(windows_subsystem, AssumedUsed, template!(NameValueStr: "windows|console")), ungated!(windows_subsystem, Normal, template!(NameValueStr: "windows|console")),
ungated!(panic_handler, Normal, template!(Word)), // RFC 2070 ungated!(panic_handler, Normal, template!(Word)), // RFC 2070
// Code generation: // Code generation:
ungated!(inline, AssumedUsed, template!(Word, List: "always|never")), ungated!(inline, Normal, template!(Word, List: "always|never")),
ungated!(cold, AssumedUsed, template!(Word)), ungated!(cold, Normal, template!(Word)),
ungated!(no_builtins, AssumedUsed, template!(Word)), ungated!(no_builtins, Normal, template!(Word)),
ungated!(target_feature, AssumedUsed, template!(List: r#"enable = "name""#)), ungated!(target_feature, Normal, template!(List: r#"enable = "name""#)),
ungated!(track_caller, AssumedUsed, template!(Word)), ungated!(track_caller, Normal, template!(Word)),
gated!( gated!(
no_sanitize, AssumedUsed, no_sanitize, Normal,
template!(List: "address, memory, thread"), template!(List: "address, memory, thread"),
experimental!(no_sanitize) experimental!(no_sanitize)
), ),
gated!(no_coverage, AssumedUsed, template!(Word), experimental!(no_coverage)), gated!(no_coverage, Normal, template!(Word), experimental!(no_coverage)),
// FIXME: #14408 assume docs are used since rustdoc looks at them. // FIXME: #14408 assume docs are used since rustdoc looks at them.
ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")), ungated!(doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string")),
// ========================================================================== // ==========================================================================
// Unstable attributes: // Unstable attributes:
// ========================================================================== // ==========================================================================
// Linking: // Linking:
gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)), gated!(naked, Normal, template!(Word), naked_functions, experimental!(naked)),
gated!( gated!(
link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib, link_ordinal, Normal, template!(List: "ordinal"), raw_dylib,
experimental!(link_ordinal) experimental!(link_ordinal)
), ),
@ -311,23 +306,23 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"custom test frameworks are an unstable feature", "custom test frameworks are an unstable feature",
), ),
// RFC #1268 // RFC #1268
gated!(marker, AssumedUsed, template!(Word), marker_trait_attr, experimental!(marker)), gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)),
gated!( gated!(
thread_local, AssumedUsed, template!(Word), thread_local, Normal, template!(Word),
"`#[thread_local]` is an experimental feature, and does not currently handle destructors", "`#[thread_local]` is an experimental feature, and does not currently handle destructors",
), ),
gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)), gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)),
// RFC 2412 // RFC 2412
gated!( gated!(
optimize, AssumedUsed, template!(List: "size|speed"), optimize_attribute, optimize, Normal, template!(List: "size|speed"), optimize_attribute,
experimental!(optimize), experimental!(optimize),
), ),
// RFC 2867 // RFC 2867
gated!(instruction_set, AssumedUsed, template!(List: "set"), isa_attribute, experimental!(instruction_set)), gated!(instruction_set, Normal, template!(List: "set"), isa_attribute, experimental!(instruction_set)),
gated!(ffi_returns_twice, AssumedUsed, template!(Word), experimental!(ffi_returns_twice)), gated!(ffi_returns_twice, Normal, template!(Word), experimental!(ffi_returns_twice)),
gated!(ffi_pure, AssumedUsed, template!(Word), experimental!(ffi_pure)), gated!(ffi_pure, Normal, template!(Word), experimental!(ffi_pure)),
gated!(ffi_const, AssumedUsed, template!(Word), experimental!(ffi_const)), gated!(ffi_const, Normal, template!(Word), experimental!(ffi_const)),
gated!( gated!(
register_attr, CrateLevel, template!(List: "attr1, attr2, ..."), register_attr, CrateLevel, template!(List: "attr1, attr2, ..."),
experimental!(register_attr), experimental!(register_attr),
@ -337,10 +332,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
experimental!(register_tool), experimental!(register_tool),
), ),
gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)), gated!(cmse_nonsecure_entry, Normal, template!(Word), experimental!(cmse_nonsecure_entry)),
// RFC 2632 // RFC 2632
gated!( gated!(
default_method_body_is_const, AssumedUsed, template!(Word), const_trait_impl, default_method_body_is_const, Normal, template!(Word), const_trait_impl,
"`default_method_body_is_const` is a temporary placeholder for declaring default bodies \ "`default_method_body_is_const` is a temporary placeholder for declaring default bodies \
as `const`, which may be removed or renamed in the future." as `const`, which may be removed or renamed in the future."
), ),
@ -353,26 +348,26 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// FIXME(#14407) -- only looked at on-demand so we can't // FIXME(#14407) -- only looked at on-demand so we can't
// guarantee they'll have already been checked. // guarantee they'll have already been checked.
ungated!( ungated!(
rustc_deprecated, AssumedUsed, rustc_deprecated, Normal,
template!(List: r#"since = "version", reason = "...""#) template!(List: r#"since = "version", reason = "...""#)
), ),
// FIXME(#14407) // FIXME(#14407)
ungated!(stable, AssumedUsed, template!(List: r#"feature = "name", since = "version""#)), ungated!(stable, Normal, template!(List: r#"feature = "name", since = "version""#)),
// FIXME(#14407) // FIXME(#14407)
ungated!( ungated!(
unstable, AssumedUsed, unstable, Normal,
template!(List: r#"feature = "name", reason = "...", issue = "N""#), template!(List: r#"feature = "name", reason = "...", issue = "N""#),
), ),
// FIXME(#14407) // FIXME(#14407)
ungated!(rustc_const_unstable, AssumedUsed, template!(List: r#"feature = "name""#)), ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#)),
// FIXME(#14407) // FIXME(#14407)
ungated!(rustc_const_stable, AssumedUsed, template!(List: r#"feature = "name""#)), ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#)),
gated!( gated!(
allow_internal_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."), allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
"allow_internal_unstable side-steps feature gating and stability checks", "allow_internal_unstable side-steps feature gating and stability checks",
), ),
gated!( gated!(
rustc_allow_const_fn_unstable, AssumedUsed, template!(Word, List: "feat1, feat2, ..."), rustc_allow_const_fn_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
"rustc_allow_const_fn_unstable side-steps feature gating and stability checks" "rustc_allow_const_fn_unstable side-steps feature gating and stability checks"
), ),
gated!( gated!(
@ -384,7 +379,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Internal attributes: Type system related: // Internal attributes: Type system related:
// ========================================================================== // ==========================================================================
gated!(fundamental, AssumedUsed, template!(Word), experimental!(fundamental)), gated!(fundamental, Normal, template!(Word), experimental!(fundamental)),
gated!( gated!(
may_dangle, Normal, template!(Word), dropck_eyepatch, may_dangle, Normal, template!(Word), dropck_eyepatch,
"`may_dangle` has unstable semantics and may be removed in the future", "`may_dangle` has unstable semantics and may be removed in the future",
@ -394,26 +389,26 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Internal attributes: Runtime related: // Internal attributes: Runtime related:
// ========================================================================== // ==========================================================================
rustc_attr!(rustc_allocator, AssumedUsed, template!(Word), IMPL_DETAIL), rustc_attr!(rustc_allocator, Normal, template!(Word), IMPL_DETAIL),
rustc_attr!(rustc_allocator_nounwind, AssumedUsed, template!(Word), IMPL_DETAIL), rustc_attr!(rustc_allocator_nounwind, Normal, template!(Word), IMPL_DETAIL),
gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)), gated!(alloc_error_handler, Normal, template!(Word), experimental!(alloc_error_handler)),
gated!( gated!(
default_lib_allocator, AssumedUsed, template!(Word), allocator_internals, default_lib_allocator, Normal, template!(Word), allocator_internals,
experimental!(default_lib_allocator), experimental!(default_lib_allocator),
), ),
gated!( gated!(
needs_allocator, Normal, template!(Word), allocator_internals, needs_allocator, Normal, template!(Word), allocator_internals,
experimental!(needs_allocator), experimental!(needs_allocator),
), ),
gated!(panic_runtime, AssumedUsed, template!(Word), experimental!(panic_runtime)), gated!(panic_runtime, Normal, template!(Word), experimental!(panic_runtime)),
gated!(needs_panic_runtime, AssumedUsed, template!(Word), experimental!(needs_panic_runtime)), gated!(needs_panic_runtime, Normal, template!(Word), experimental!(needs_panic_runtime)),
gated!( gated!(
compiler_builtins, AssumedUsed, template!(Word), compiler_builtins, Normal, template!(Word),
"the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \ "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!( gated!(
profiler_runtime, AssumedUsed, template!(Word), profiler_runtime, Normal, template!(Word),
"the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \ "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",
), ),
@ -423,23 +418,23 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ========================================================================== // ==========================================================================
gated!( gated!(
linkage, AssumedUsed, template!(NameValueStr: "external|internal|..."), linkage, Normal, template!(NameValueStr: "external|internal|..."),
"the `linkage` attribute is experimental and not portable across platforms", "the `linkage` attribute is experimental and not portable across platforms",
), ),
rustc_attr!(rustc_std_internal_symbol, AssumedUsed, template!(Word), INTERNAL_UNSTABLE), rustc_attr!(rustc_std_internal_symbol, Normal, template!(Word), INTERNAL_UNSTABLE),
// ========================================================================== // ==========================================================================
// Internal attributes, Macro related: // Internal attributes, Macro related:
// ========================================================================== // ==========================================================================
rustc_attr!( rustc_attr!(
rustc_builtin_macro, AssumedUsed, rustc_builtin_macro, Normal,
template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"), template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"),
IMPL_DETAIL, IMPL_DETAIL,
), ),
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE), rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
rustc_attr!( rustc_attr!(
rustc_macro_transparency, AssumedUsed, rustc_macro_transparency, Normal,
template!(NameValueStr: "transparent|semitransparent|opaque"), template!(NameValueStr: "transparent|semitransparent|opaque"),
"used internally for testing macro hygiene", "used internally for testing macro hygiene",
), ),
@ -449,7 +444,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ========================================================================== // ==========================================================================
rustc_attr!( rustc_attr!(
rustc_on_unimplemented, AssumedUsed, rustc_on_unimplemented, Normal,
template!( template!(
List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#, List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
NameValueStr: "message" NameValueStr: "message"
@ -457,31 +452,31 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
INTERNAL_UNSTABLE INTERNAL_UNSTABLE
), ),
// Enumerates "identity-like" conversion methods to suggest on type mismatch. // Enumerates "identity-like" conversion methods to suggest on type mismatch.
rustc_attr!(rustc_conversion_suggestion, AssumedUsed, template!(Word), INTERNAL_UNSTABLE), rustc_attr!(rustc_conversion_suggestion, Normal, template!(Word), INTERNAL_UNSTABLE),
// ========================================================================== // ==========================================================================
// Internal attributes, Const related: // Internal attributes, Const related:
// ========================================================================== // ==========================================================================
rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), rustc_attr!(rustc_promotable, Normal, template!(Word), IMPL_DETAIL),
rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), rustc_attr!(rustc_legacy_const_generics, Normal, template!(List: "N"), INTERNAL_UNSTABLE),
// ========================================================================== // ==========================================================================
// Internal attributes, Layout related: // Internal attributes, Layout related:
// ========================================================================== // ==========================================================================
rustc_attr!( rustc_attr!(
rustc_layout_scalar_valid_range_start, AssumedUsed, template!(List: "value"), rustc_layout_scalar_valid_range_start, Normal, template!(List: "value"),
"the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \ "the `#[rustc_layout_scalar_valid_range_start]` attribute is just used to enable \
niche optimizations in libcore and will never be stable", niche optimizations in libcore and will never be stable",
), ),
rustc_attr!( rustc_attr!(
rustc_layout_scalar_valid_range_end, AssumedUsed, template!(List: "value"), rustc_layout_scalar_valid_range_end, Normal, template!(List: "value"),
"the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \ "the `#[rustc_layout_scalar_valid_range_end]` attribute is just used to enable \
niche optimizations in libcore and will never be stable", niche optimizations in libcore and will never be stable",
), ),
rustc_attr!( rustc_attr!(
rustc_nonnull_optimization_guaranteed, AssumedUsed, template!(Word), rustc_nonnull_optimization_guaranteed, Normal, template!(Word),
"the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \ "the `#[rustc_nonnull_optimization_guaranteed]` attribute is just used to enable \
niche optimizations in libcore and will never be stable", niche optimizations in libcore and will never be stable",
), ),
@ -506,7 +501,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
), ),
gated!( gated!(
// Used in resolve: // Used in resolve:
prelude_import, AssumedUsed, template!(Word), prelude_import, Normal, template!(Word),
"`#[prelude_import]` is for use by rustc only", "`#[prelude_import]` is for use by rustc only",
), ),
gated!( gated!(
@ -514,7 +509,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"unboxed_closures are still evolving", "unboxed_closures are still evolving",
), ),
rustc_attr!( rustc_attr!(
rustc_inherit_overflow_checks, AssumedUsed, template!(Word), rustc_inherit_overflow_checks, Normal, template!(Word),
"the `#[rustc_inherit_overflow_checks]` attribute is just used to control \ "the `#[rustc_inherit_overflow_checks]` attribute is just used to control \
overflow checking behavior of several libcore functions that are inlined \ overflow checking behavior of several libcore functions that are inlined \
across crates and will never be stable", across crates and will never be stable",
@ -556,41 +551,41 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")), rustc_attr!(TEST, rustc_layout, Normal, template!(List: "field1, field2, ...")),
rustc_attr!(TEST, rustc_regions, Normal, template!(Word)), rustc_attr!(TEST, rustc_regions, Normal, template!(Word)),
rustc_attr!( rustc_attr!(
TEST, rustc_error, AssumedUsed, TEST, rustc_error, Normal,
template!(Word, List: "delay_span_bug_from_inside_query") template!(Word, List: "delay_span_bug_from_inside_query")
), ),
rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word)),
rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word)),
rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")), rustc_attr!(TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode")),
rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")), rustc_attr!(TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode")),
rustc_attr!( rustc_attr!(
TEST, rustc_clean, AssumedUsed, TEST, rustc_clean, Normal,
template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
), ),
rustc_attr!( rustc_attr!(
TEST, rustc_partition_reused, AssumedUsed, TEST, rustc_partition_reused, Normal,
template!(List: r#"cfg = "...", module = "...""#), template!(List: r#"cfg = "...", module = "...""#),
), ),
rustc_attr!( rustc_attr!(
TEST, rustc_partition_codegened, AssumedUsed, TEST, rustc_partition_codegened, Normal,
template!(List: r#"cfg = "...", module = "...""#), template!(List: r#"cfg = "...", module = "...""#),
), ),
rustc_attr!( rustc_attr!(
TEST, rustc_expected_cgu_reuse, AssumedUsed, TEST, rustc_expected_cgu_reuse, Normal,
template!(List: r#"cfg = "...", module = "...", kind = "...""#), template!(List: r#"cfg = "...", module = "...", kind = "...""#),
), ),
rustc_attr!(TEST, rustc_synthetic, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_synthetic, Normal, template!(Word)),
rustc_attr!(TEST, rustc_symbol_name, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word)),
rustc_attr!(TEST, rustc_polymorphize_error, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word)),
rustc_attr!(TEST, rustc_def_path, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_def_path, Normal, template!(Word)),
rustc_attr!(TEST, rustc_mir, AssumedUsed, template!(List: "arg1, arg2, ...")), rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ...")),
rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word)),
rustc_attr!(TEST, rustc_dump_env_program_clauses, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word)),
rustc_attr!(TEST, rustc_object_lifetime_default, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word)),
rustc_attr!(TEST, rustc_dump_vtable, AssumedUsed, template!(Word)), rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word)),
rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)), rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
gated!( gated!(
omit_gdb_pretty_printer_section, AssumedUsed, template!(Word), omit_gdb_pretty_printer_section, Normal, template!(Word),
"the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite", "the `#[omit_gdb_pretty_printer_section]` attribute is just used for the Rust test suite",
), ),
]; ];

View File

@ -123,7 +123,7 @@ impl IfThisChanged<'tcx> {
let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id()); let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id());
let attrs = self.tcx.hir().attrs(hir_id); let attrs = self.tcx.hir().attrs(hir_id);
for attr in attrs { for attr in attrs {
if self.tcx.sess.check_name(attr, sym::rustc_if_this_changed) { if attr.has_name(sym::rustc_if_this_changed) {
let dep_node_interned = self.argument(attr); let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned { let dep_node = match dep_node_interned {
None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner), None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner),
@ -138,7 +138,7 @@ impl IfThisChanged<'tcx> {
}, },
}; };
self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node)); self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node));
} else if self.tcx.sess.check_name(attr, sym::rustc_then_this_would_need) { } else if attr.has_name(sym::rustc_then_this_would_need) {
let dep_node_interned = self.argument(attr); let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned { let dep_node = match dep_node_interned {
Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) { Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {

View File

@ -57,27 +57,26 @@ struct AssertModuleSource<'tcx> {
impl AssertModuleSource<'tcx> { impl AssertModuleSource<'tcx> {
fn check_attr(&self, attr: &ast::Attribute) { fn check_attr(&self, attr: &ast::Attribute) {
let (expected_reuse, comp_kind) = let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) {
if self.tcx.sess.check_name(attr, sym::rustc_partition_reused) { (CguReuse::PreLto, ComparisonKind::AtLeast)
(CguReuse::PreLto, ComparisonKind::AtLeast) } else if attr.has_name(sym::rustc_partition_codegened) {
} else if self.tcx.sess.check_name(attr, sym::rustc_partition_codegened) { (CguReuse::No, ComparisonKind::Exact)
(CguReuse::No, ComparisonKind::Exact) } else if attr.has_name(sym::rustc_expected_cgu_reuse) {
} else if self.tcx.sess.check_name(attr, sym::rustc_expected_cgu_reuse) { match self.field(attr, sym::kind) {
match self.field(attr, sym::kind) { sym::no => (CguReuse::No, ComparisonKind::Exact),
sym::no => (CguReuse::No, ComparisonKind::Exact), sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact), sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact), sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast), other => {
other => { self.tcx.sess.span_fatal(
self.tcx.sess.span_fatal( attr.span,
attr.span, &format!("unknown cgu-reuse-kind `{}` specified", other),
&format!("unknown cgu-reuse-kind `{}` specified", other), );
);
}
} }
} else { }
return; } else {
}; return;
};
if !self.tcx.sess.opts.debugging_opts.query_dep_graph { if !self.tcx.sess.opts.debugging_opts.query_dep_graph {
self.tcx.sess.span_fatal( self.tcx.sess.span_fatal(

View File

@ -159,7 +159,7 @@ pub struct DirtyCleanVisitor<'tcx> {
impl DirtyCleanVisitor<'tcx> { impl DirtyCleanVisitor<'tcx> {
/// Possibly "deserialize" the attribute into a clean/dirty assertion /// Possibly "deserialize" the attribute into a clean/dirty assertion
fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> { fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> {
if !self.tcx.sess.check_name(attr, sym::rustc_clean) { if !attr.has_name(sym::rustc_clean) {
// skip: not rustc_clean/dirty // skip: not rustc_clean/dirty
return None; return None;
} }
@ -427,7 +427,7 @@ pub struct FindAllAttrs<'tcx> {
impl FindAllAttrs<'tcx> { impl FindAllAttrs<'tcx> {
fn is_active_attr(&mut self, attr: &Attribute) -> bool { fn is_active_attr(&mut self, attr: &Attribute) -> bool {
if self.tcx.sess.check_name(attr, sym::rustc_clean) && check_config(self.tcx, attr) { if attr.has_name(sym::rustc_clean) && check_config(self.tcx, attr) {
return true; return true;
} }

View File

@ -266,7 +266,7 @@ impl<'tcx> Queries<'tcx> {
}; };
let attrs = &*tcx.get_attrs(def_id); let attrs = &*tcx.get_attrs(def_id);
let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error)); let attrs = attrs.iter().filter(|attr| attr.has_name(sym::rustc_error));
for attr in attrs { for attr in attrs {
match attr.meta_item_list() { match attr.meta_item_list() {
// Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`. // Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`.

View File

@ -488,13 +488,13 @@ pub fn get_codegen_sysroot(
} }
pub(crate) fn check_attr_crate_type( pub(crate) fn check_attr_crate_type(
sess: &Session, _sess: &Session,
attrs: &[ast::Attribute], attrs: &[ast::Attribute],
lint_buffer: &mut LintBuffer, lint_buffer: &mut LintBuffer,
) { ) {
// Unconditionally collect crate types from attributes to make them used // Unconditionally collect crate types from attributes to make them used
for a in attrs.iter() { for a in attrs.iter() {
if sess.check_name(a, sym::crate_type) { if a.has_name(sym::crate_type) {
if let Some(n) = a.value_str() { if let Some(n) = a.value_str() {
if categorize_crate_type(n).is_some() { if categorize_crate_type(n).is_some() {
return; return;
@ -552,7 +552,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec<C
let attr_types: Vec<CrateType> = attrs let attr_types: Vec<CrateType> = attrs
.iter() .iter()
.filter_map(|a| { .filter_map(|a| {
if session.check_name(a, sym::crate_type) { if a.has_name(sym::crate_type) {
match a.value_str() { match a.value_str() {
Some(s) => categorize_crate_type(s), Some(s) => categorize_crate_type(s),
_ => None, _ => None,

View File

@ -46,7 +46,6 @@ use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::Instance; use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt}; use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
use rustc_session::lint::FutureIncompatibilityReason; use rustc_session::lint::FutureIncompatibilityReason;
use rustc_session::Session;
use rustc_span::edition::Edition; use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned; use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::symbol::{kw, sym, Ident, Symbol};
@ -344,7 +343,7 @@ impl UnsafeCode {
impl EarlyLintPass for UnsafeCode { impl EarlyLintPass for UnsafeCode {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
if cx.sess().check_name(attr, sym::allow_internal_unsafe) { if attr.has_name(sym::allow_internal_unsafe) {
self.report_unsafe(cx, attr.span, |lint| { self.report_unsafe(cx, attr.span, |lint| {
lint.build( lint.build(
"`allow_internal_unsafe` allows defining \ "`allow_internal_unsafe` allows defining \
@ -492,12 +491,12 @@ pub struct MissingDoc {
impl_lint_pass!(MissingDoc => [MISSING_DOCS]); impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
fn has_doc(sess: &Session, attr: &ast::Attribute) -> bool { fn has_doc(attr: &ast::Attribute) -> bool {
if attr.is_doc_comment() { if attr.is_doc_comment() {
return true; return true;
} }
if !sess.check_name(attr, sym::doc) { if !attr.has_name(sym::doc) {
return false; return false;
} }
@ -554,7 +553,7 @@ impl MissingDoc {
} }
let attrs = cx.tcx.get_attrs(def_id.to_def_id()); let attrs = cx.tcx.get_attrs(def_id.to_def_id());
let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a)); let has_doc = attrs.iter().any(has_doc);
if !has_doc { if !has_doc {
cx.struct_span_lint( cx.struct_span_lint(
MISSING_DOCS, MISSING_DOCS,
@ -568,10 +567,10 @@ impl MissingDoc {
} }
impl<'tcx> LateLintPass<'tcx> for MissingDoc { impl<'tcx> LateLintPass<'tcx> for MissingDoc {
fn enter_lint_attrs(&mut self, cx: &LateContext<'_>, attrs: &[ast::Attribute]) { fn enter_lint_attrs(&mut self, _cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
let doc_hidden = self.doc_hidden() let doc_hidden = self.doc_hidden()
|| attrs.iter().any(|attr| { || attrs.iter().any(|attr| {
cx.sess().check_name(attr, sym::doc) attr.has_name(sym::doc)
&& match attr.meta_item_list() { && match attr.meta_item_list() {
None => false, None => false,
Some(l) => attr::list_contains_name(&l, sym::hidden), Some(l) => attr::list_contains_name(&l, sym::hidden),
@ -595,7 +594,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
} }
let attrs = cx.tcx.hir().attrs(macro_def.hir_id()); let attrs = cx.tcx.hir().attrs(macro_def.hir_id());
let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a)); let has_doc = attrs.iter().any(has_doc);
if !has_doc { if !has_doc {
cx.struct_span_lint( cx.struct_span_lint(
MISSING_DOCS, MISSING_DOCS,
@ -999,7 +998,7 @@ impl EarlyLintPass for DeprecatedAttr {
return; return;
} }
} }
if cx.sess().check_name(attr, sym::no_start) || cx.sess().check_name(attr, sym::crate_id) { if attr.has_name(sym::no_start) || attr.has_name(sym::crate_id) {
let path_str = pprust::path_to_string(&attr.get_normal_item().path); let path_str = pprust::path_to_string(&attr.get_normal_item().path);
let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str); let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
lint_deprecated_attr(cx, attr, &msg, None); lint_deprecated_attr(cx, attr, &msg, None);
@ -1028,7 +1027,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
let span = sugared_span.take().unwrap_or(attr.span); let span = sugared_span.take().unwrap_or(attr.span);
if is_doc_comment || cx.sess().check_name(attr, sym::doc) { if is_doc_comment || attr.has_name(sym::doc) {
cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
let mut err = lint.build("unused doc comment"); let mut err = lint.build("unused doc comment");
err.span_label( err.span_label(
@ -1301,7 +1300,7 @@ declare_lint_pass!(
impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
if cx.sess().check_name(attr, sym::feature) { if attr.has_name(sym::feature) {
if let Some(items) = attr.meta_item_list() { if let Some(items) = attr.meta_item_list() {
for item in items { for item in items {
cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| { cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
@ -2771,7 +2770,7 @@ impl ClashingExternDeclarations {
overridden_link_name, overridden_link_name,
tcx.get_attrs(fi.def_id.to_def_id()) tcx.get_attrs(fi.def_id.to_def_id())
.iter() .iter()
.find(|at| tcx.sess.check_name(at, sym::link_name)) .find(|at| at.has_name(sym::link_name))
.unwrap() .unwrap()
.span, .span,
) )

View File

@ -236,8 +236,6 @@ impl<'s> LintLevelsBuilder<'s> {
Some(lvl) => lvl, Some(lvl) => lvl,
}; };
self.sess.mark_attr_used(attr);
let mut metas = unwrap_or!(attr.meta_item_list(), continue); let mut metas = unwrap_or!(attr.meta_item_list(), continue);
if metas.is_empty() { if metas.is_empty() {

View File

@ -151,8 +151,6 @@ macro_rules! late_lint_passes {
// FIXME: Look into regression when this is used as a module lint // FIXME: Look into regression when this is used as a module lint
// May Depend on constants elsewhere // May Depend on constants elsewhere
UnusedBrokenConst: UnusedBrokenConst, UnusedBrokenConst: UnusedBrokenConst,
// Uses attr::is_used which is untracked, can't be an incremental module pass.
UnusedAttributes: UnusedAttributes::new(),
// Needs to run after UnusedAttributes as it marks all `feature` attributes as used. // Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
UnstableFeatures: UnstableFeatures, UnstableFeatures: UnstableFeatures,
// Tracks state across modules // Tracks state across modules

View File

@ -669,9 +669,7 @@ enum FfiResult<'tcx> {
} }
crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtDef) -> bool { crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtDef) -> bool {
tcx.get_attrs(def.did) tcx.get_attrs(def.did).iter().any(|a| a.has_name(sym::rustc_nonnull_optimization_guaranteed))
.iter()
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
} }
/// `repr(transparent)` structs can have a single non-ZST field, this function returns that /// `repr(transparent)` structs can have a single non-ZST field, this function returns that

View File

@ -4,21 +4,16 @@ use rustc_ast as ast;
use rustc_ast::util::parser; use rustc_ast::util::parser;
use rustc_ast::{ExprKind, StmtKind}; use rustc_ast::{ExprKind, StmtKind};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, Applicability}; use rustc_errors::{pluralize, Applicability};
use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res}; use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::ty::adjustment; use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
use rustc_span::symbol::Symbol; use rustc_span::symbol::Symbol;
use rustc_span::symbol::{kw, sym}; use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, DUMMY_SP}; use rustc_span::{BytePos, Span, DUMMY_SP};
use tracing::debug;
declare_lint! { declare_lint! {
/// The `unused_must_use` lint detects unused result of a type flagged as /// The `unused_must_use` lint detects unused result of a type flagged as
/// `#[must_use]`. /// `#[must_use]`.
@ -308,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_post_path: &str, descr_post_path: &str,
) -> bool { ) -> bool {
for attr in cx.tcx.get_attrs(def_id).iter() { for attr in cx.tcx.get_attrs(def_id).iter() {
if cx.sess().check_name(attr, sym::must_use) { if attr.has_name(sym::must_use) {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| { cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let msg = format!( let msg = format!(
"unused {}`{}`{} that must be used", "unused {}`{}`{} that must be used",
@ -382,62 +377,6 @@ impl<'tcx> LateLintPass<'tcx> for PathStatements {
} }
} }
#[derive(Copy, Clone)]
pub struct UnusedAttributes {
builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,
}
impl UnusedAttributes {
pub fn new() -> Self {
UnusedAttributes { builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP }
}
}
impl_lint_pass!(UnusedAttributes => [UNUSED_ATTRIBUTES]);
impl<'tcx> LateLintPass<'tcx> for UnusedAttributes {
fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
debug!("checking attribute: {:?}", attr);
if attr.is_doc_comment() {
return;
}
let attr_info = attr.ident().and_then(|ident| self.builtin_attributes.get(&ident.name));
if let Some(&&(name, ty, ..)) = attr_info {
if let AttributeType::AssumedUsed = ty {
debug!("{:?} is AssumedUsed", name);
return;
}
}
if !cx.sess().is_attr_used(attr) {
debug!("emitting warning for: {:?}", attr);
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
// Mark as used to avoid duplicate warnings.
cx.sess().mark_attr_used(attr);
lint.build("unused attribute").emit()
});
// Is it a builtin attribute that must be used at the crate level?
if attr_info.map_or(false, |(_, ty, ..)| ty == &AttributeType::CrateLevel) {
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
let msg = match attr.style {
ast::AttrStyle::Outer => {
"crate-level attribute should be an inner attribute: add an exclamation \
mark: `#![foo]`"
}
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
};
lint.build(msg).emit()
});
}
} else {
debug!("Attr was used: {:?}", attr);
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum UnusedDelimsCtx { enum UnusedDelimsCtx {
FunctionArg, FunctionArg,

View File

@ -3042,6 +3042,7 @@ declare_lint_pass! {
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
UNSUPPORTED_CALLING_CONVENTIONS, UNSUPPORTED_CALLING_CONVENTIONS,
BREAK_WITH_LABEL_AND_LOOP, BREAK_WITH_LABEL_AND_LOOP,
UNUSED_ATTRIBUTES,
] ]
} }

View File

@ -44,8 +44,7 @@ impl ItemLikeVisitor<'tcx> for Collector<'tcx> {
// Process all of the #[link(..)]-style arguments // Process all of the #[link(..)]-style arguments
let sess = &self.tcx.sess; let sess = &self.tcx.sess;
for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| sess.check_name(a, sym::link)) for m in self.tcx.hir().attrs(it.hir_id()).iter().filter(|a| a.has_name(sym::link)) {
{
let items = match m.meta_item_list() { let items = match m.meta_item_list() {
Some(item) => item, Some(item) => item,
None => continue, None => continue,

View File

@ -48,7 +48,7 @@ pub fn get_recursion_limit(krate_attrs: &[Attribute], sess: &Session) -> Limit {
fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: usize) -> Limit { fn get_limit(krate_attrs: &[Attribute], sess: &Session, name: Symbol, default: usize) -> Limit {
for attr in krate_attrs { for attr in krate_attrs {
if !sess.check_name(attr, name) { if !attr.has_name(name) {
continue; continue;
} }

View File

@ -1136,7 +1136,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) { pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
let attrs = self.get_attrs(def_id); let attrs = self.get_attrs(def_id);
let get = |name| { let get = |name| {
let attr = match attrs.iter().find(|a| self.sess.check_name(a, name)) { let attr = match attrs.iter().find(|a| a.has_name(name)) {
Some(attr) => attr, Some(attr) => attr,
None => return Bound::Unbounded, None => return Bound::Unbounded,
}; };

View File

@ -338,7 +338,7 @@ impl RustcMirAttrs {
let rustc_mir_attrs = attrs let rustc_mir_attrs = attrs
.iter() .iter()
.filter(|attr| tcx.sess.check_name(attr, sym::rustc_mir)) .filter(|attr| attr.has_name(sym::rustc_mir))
.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 {

View File

@ -30,12 +30,12 @@ pub struct MoveDataParamEnv<'tcx> {
} }
pub(crate) fn has_rustc_mir_with( pub(crate) fn has_rustc_mir_with(
sess: &Session, _sess: &Session,
attrs: &[ast::Attribute], attrs: &[ast::Attribute],
name: Symbol, name: Symbol,
) -> Option<MetaItem> { ) -> Option<MetaItem> {
for attr in attrs { for attr in attrs {
if sess.check_name(attr, sym::rustc_mir) { if attr.has_name(sym::rustc_mir) {
let items = attr.meta_item_list(); let items = attr.meta_item_list();
for item in items.iter().flat_map(|l| l.iter()) { for item in items.iter().flat_map(|l| l.iter()) {
match item.meta_item() { match item.meta_item() {

View File

@ -204,11 +204,7 @@ fn emit_unused_generic_params_error<'tcx>(
unused_parameters: &FiniteBitSet<u32>, unused_parameters: &FiniteBitSet<u32>,
) { ) {
let base_def_id = tcx.closure_base_def_id(def_id); let base_def_id = tcx.closure_base_def_id(def_id);
if !tcx if !tcx.get_attrs(base_def_id).iter().any(|a| a.has_name(sym::rustc_polymorphize_error)) {
.get_attrs(base_def_id)
.iter()
.any(|a| tcx.sess.check_name(a, sym::rustc_polymorphize_error))
{
return; return;
} }

View File

@ -13,9 +13,10 @@ use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
use rustc_ast::tokenstream::{Spacing, TokenStream}; use rustc_ast::tokenstream::{Spacing, TokenStream};
use rustc_ast::AstLike; use rustc_ast::AstLike;
use rustc_ast::Attribute; use rustc_ast::Attribute;
use rustc_ast::{AttrItem, MetaItem};
use rustc_ast_pretty::pprust; use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc; use rustc_data_structures::sync::Lrc;
use rustc_errors::{Diagnostic, FatalError, Level, PResult}; use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult};
use rustc_session::parse::ParseSess; use rustc_session::parse::ParseSess;
use rustc_span::{FileName, SourceFile, Span}; use rustc_span::{FileName, SourceFile, Span};
@ -324,3 +325,44 @@ pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream {
let filename = FileName::macro_expansion_source_code(&source); let filename = FileName::macro_expansion_source_code(&source);
parse_stream_from_source_str(filename, source, sess, Some(nt.span())) parse_stream_from_source_str(filename, source, sess, Some(nt.span()))
} }
pub fn parse_cfg_attr(
attr: &Attribute,
parse_sess: &ParseSess,
) -> Option<(MetaItem, Vec<(AttrItem, Span)>)> {
match attr.get_normal_item().args {
ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
let msg = "wrong `cfg_attr` delimiters";
crate::validate_attr::check_meta_bad_delim(parse_sess, dspan, delim, msg);
match parse_in(parse_sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
Ok(r) => return Some(r),
Err(mut e) => {
e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
.note(CFG_ATTR_NOTE_REF)
.emit();
}
}
}
_ => error_malformed_cfg_attr_missing(attr.span, parse_sess),
}
None
}
const CFG_ATTR_GRAMMAR_HELP: &str = "#[cfg_attr(condition, attribute, other_attribute, ...)]";
const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
<https://doc.rust-lang.org/reference/conditional-compilation.html\
#the-cfg_attr-attribute>";
fn error_malformed_cfg_attr_missing(span: Span, parse_sess: &ParseSess) {
parse_sess
.span_diagnostic
.struct_span_err(span, "malformed `cfg_attr` attribute input")
.span_suggestion(
span,
"missing condition and attribute",
CFG_ATTR_GRAMMAR_HELP.to_string(),
Applicability::HasPlaceholders,
)
.note(CFG_ATTR_NOTE_REF)
.emit();
}

View File

@ -11,6 +11,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" } rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" } rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" } rustc_index = { path = "../rustc_index" }
rustc_parse = { path = "../rustc_parse" }
rustc_session = { path = "../rustc_session" } rustc_session = { path = "../rustc_session" }
rustc_target = { path = "../rustc_target" } rustc_target = { path = "../rustc_target" }
rustc_ast = { path = "../rustc_ast" } rustc_ast = { path = "../rustc_ast" }
@ -18,3 +19,4 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" } rustc_span = { path = "../rustc_span" }
rustc_lexer = { path = "../rustc_lexer" } rustc_lexer = { path = "../rustc_lexer" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" } rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_feature = { path = "../rustc_feature" }

View File

@ -8,8 +8,10 @@ use rustc_middle::hir::map::Map;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_ast::{AttrStyle, Attribute, Lit, LitKind, NestedMetaItem}; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, NestedMetaItem};
use rustc_data_structures::stable_set::FxHashSet;
use rustc_errors::{pluralize, struct_span_err, Applicability}; use rustc_errors::{pluralize, struct_span_err, Applicability};
use rustc_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
@ -66,9 +68,10 @@ impl CheckAttrVisitor<'tcx> {
) { ) {
let mut is_valid = true; let mut is_valid = true;
let mut specified_inline = None; let mut specified_inline = None;
let mut seen = FxHashSet::default();
let attrs = self.tcx.hir().attrs(hir_id); let attrs = self.tcx.hir().attrs(hir_id);
for attr in attrs { for attr in attrs {
is_valid &= match attr.name_or_empty() { let attr_is_valid = match attr.name_or_empty() {
sym::inline => self.check_inline(hir_id, attr, span, target), sym::inline => self.check_inline(hir_id, attr, span, target),
sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target), sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
sym::marker => self.check_marker(hir_id, attr, span, target), sym::marker => self.check_marker(hir_id, attr, span, target),
@ -101,14 +104,66 @@ impl CheckAttrVisitor<'tcx> {
sym::default_method_body_is_const => { sym::default_method_body_is_const => {
self.check_default_method_body_is_const(attr, span, target) self.check_default_method_body_is_const(attr, span, target)
} }
sym::rustc_const_unstable
| sym::rustc_const_stable
| sym::unstable
| sym::stable
| sym::rustc_promotable => self.check_stability_promotable(&attr, span, target),
_ => true, _ => true,
}; };
is_valid &= attr_is_valid;
// lint-only checks // lint-only checks
match attr.name_or_empty() { match attr.name_or_empty() {
sym::cold => self.check_cold(hir_id, attr, span, target), sym::cold => self.check_cold(hir_id, attr, span, target),
sym::link_name => self.check_link_name(hir_id, attr, span, target), sym::link_name => self.check_link_name(hir_id, attr, span, target),
sym::link_section => self.check_link_section(hir_id, attr, span, target), sym::link_section => self.check_link_section(hir_id, attr, span, target),
sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target), sym::no_mangle => self.check_no_mangle(hir_id, attr, span, target),
sym::deprecated | sym::rustc_deprecated => {
self.check_deprecated(hir_id, attr, span, target)
}
sym::macro_use | sym::macro_escape => self.check_macro_use(hir_id, attr, target),
sym::path => self.check_generic_attr(hir_id, attr, target, &[Target::Mod]),
sym::cfg_attr => self.check_cfg_attr(hir_id, attr),
sym::plugin_registrar => self.check_plugin_registrar(hir_id, attr, target),
sym::macro_export => self.check_macro_export(hir_id, attr, target),
sym::ignore | sym::should_panic | sym::proc_macro_derive => {
self.check_generic_attr(hir_id, attr, target, &[Target::Fn])
}
_ => {}
}
if hir_id != CRATE_HIR_ID {
if let Some((_, AttributeType::CrateLevel, ..)) =
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name))
{
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
let msg = match attr.style {
ast::AttrStyle::Outer => {
"crate-level attribute should be an inner attribute: add an exclamation \
mark: `#![foo]`"
}
ast::AttrStyle::Inner => "crate-level attribute should be in the root module",
};
lint.build(msg).emit()
});
}
}
// Duplicate attributes
match attr.name_or_empty() {
name @ sym::macro_use => {
let args = attr.meta_item_list().unwrap_or_else(Vec::new);
let args: Vec<_> = args.iter().map(|arg| arg.name_or_empty()).collect();
if !seen.insert((name, args)) {
self.tcx.struct_span_lint_hir(
UNUSED_ATTRIBUTES,
hir_id,
attr.span,
|lint| lint.build("unused attribute").emit(),
);
}
}
_ => {} _ => {}
} }
} }
@ -211,6 +266,38 @@ impl CheckAttrVisitor<'tcx> {
} }
} }
fn check_generic_attr(
&self,
hir_id: HirId,
attr: &Attribute,
target: Target,
allowed_targets: &[Target],
) {
if !allowed_targets.iter().any(|t| t == &target) {
let name = attr.name_or_empty();
let mut i = allowed_targets.iter();
// Pluralize
let b = i.next().map_or_else(String::new, |t| t.to_string() + "s");
let supported_names = i.enumerate().fold(b, |mut b, (i, allowed_target)| {
if allowed_targets.len() > 2 && i == allowed_targets.len() - 2 {
b.push_str(", and ");
} else if allowed_targets.len() == 2 && i == allowed_targets.len() - 2 {
b.push_str(" and ");
} else {
b.push_str(", ");
}
// Pluralize
b.push_str(&(allowed_target.to_string() + "s"));
b
});
//let supported_names = allowed_targets.iter().fold(String::new(), |msg, t| msg + ", " + &t.to_string());
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build(&format!("`#[{name}]` only has an effect on {}", supported_names))
.emit();
});
}
}
/// Checks if `#[naked]` is applied to a function definition. /// Checks if `#[naked]` is applied to a function definition.
fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool { fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target { match target {
@ -1555,6 +1642,72 @@ impl CheckAttrVisitor<'tcx> {
} }
} }
} }
fn check_stability_promotable(&self, attr: &Attribute, _span: &Span, target: Target) -> bool {
match target {
Target::Expression => {
self.tcx
.sess
.struct_span_err(attr.span, "attribute cannot be applied to an expression")
.emit();
false
}
_ => true,
}
}
fn check_deprecated(&self, hir_id: HirId, attr: &Attribute, _span: &Span, target: Target) {
match target {
Target::Closure | Target::Expression | Target::Statement | Target::Arm => {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build("attribute is ignored here").emit();
});
}
_ => {}
}
}
fn check_macro_use(&self, hir_id: HirId, attr: &Attribute, target: Target) {
let name = attr.name_or_empty();
match target {
Target::ExternCrate | Target::Mod => {}
_ => {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build(&format!(
"`#[{name}]` only has an effect on `extern crate` and modules"
))
.emit();
});
}
}
}
fn check_macro_export(&self, hir_id: HirId, attr: &Attribute, target: Target) {
if target != Target::MacroDef {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build(&format!("`#[macro_export]` only has an effect on macro definitions"))
.emit();
});
}
}
fn check_cfg_attr(&self, hir_id: HirId, attr: &Attribute) {
if let Some((_, attrs)) = rustc_parse::parse_cfg_attr(&attr, &self.tcx.sess.parse_sess) {
if attrs.is_empty() {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build("`#[cfg_attr]` does not expand to any attributes").emit();
});
}
}
}
fn check_plugin_registrar(&self, hir_id: HirId, attr: &Attribute, target: Target) {
if target != Target::Fn {
self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| {
lint.build("`#[plugin_registrar]` only has an effect on functions").emit();
});
}
}
} }
impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
@ -1675,7 +1828,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
for attr in attrs { for attr in attrs {
for attr_to_check in ATTRS_TO_CHECK { for attr_to_check in ATTRS_TO_CHECK {
if tcx.sess.check_name(attr, *attr_to_check) { if attr.has_name(*attr_to_check) {
tcx.sess tcx.sess
.struct_span_err( .struct_span_err(
attr.span, attr.span,
@ -1692,7 +1845,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
fn check_invalid_macro_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { fn check_invalid_macro_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
for attr in attrs { for attr in attrs {
if tcx.sess.check_name(attr, sym::inline) { if attr.has_name(sym::inline) {
struct_span_err!( struct_span_err!(
tcx.sess, tcx.sess,
attr.span, attr.span,

View File

@ -15,7 +15,6 @@ use rustc_hir as hir;
use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::query::Providers; use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_span::symbol::{sym, Symbol}; use rustc_span::symbol::{sym, Symbol};
@ -51,7 +50,7 @@ impl<'tcx> DiagnosticItemCollector<'tcx> {
fn observe_item(&mut self, def_id: LocalDefId) { fn observe_item(&mut self, def_id: LocalDefId) {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
let attrs = self.tcx.hir().attrs(hir_id); let attrs = self.tcx.hir().attrs(hir_id);
if let Some(name) = extract(&self.tcx.sess, attrs) { if let Some(name) = extract(attrs) {
// insert into our table // insert into our table
collect_item(self.tcx, &mut self.items, name, def_id.to_def_id()); collect_item(self.tcx, &mut self.items, name, def_id.to_def_id());
} }
@ -91,10 +90,10 @@ fn collect_item(
} }
} }
/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes. /// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.p
fn extract(sess: &Session, attrs: &[ast::Attribute]) -> Option<Symbol> { fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
attrs.iter().find_map(|attr| { attrs.iter().find_map(|attr| {
if sess.check_name(attr, sym::rustc_diagnostic_item) { attr.value_str() } else { None } if attr.has_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None }
}) })
} }

View File

@ -13,6 +13,7 @@ use crate::weak_lang_items;
use rustc_middle::middle::cstore::ExternCrate; use rustc_middle::middle::cstore::ExternCrate;
use rustc_middle::ty::TyCtxt; use rustc_middle::ty::TyCtxt;
use rustc_ast::Attribute;
use rustc_errors::{pluralize, struct_span_err}; use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir; use rustc_hir as hir;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
@ -57,7 +58,7 @@ impl LanguageItemCollector<'tcx> {
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) {
let attrs = self.tcx.hir().attrs(hir_id); let attrs = self.tcx.hir().attrs(hir_id);
let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym); let check_name = |attr: &Attribute, sym| attr.has_name(sym);
if let Some((value, span)) = extract(check_name, &attrs) { if let Some((value, span)) = extract(check_name, &attrs) {
match ITEM_REFS.get(&value).cloned() { match ITEM_REFS.get(&value).cloned() {
// Known lang item with attribute on correct target. // Known lang item with attribute on correct target.

View File

@ -27,7 +27,7 @@ impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
| ItemKind::Struct(..) | ItemKind::Struct(..)
| ItemKind::Union(..) => { | ItemKind::Union(..) => {
for attr in self.tcx.get_attrs(item.def_id.to_def_id()).iter() { for attr in self.tcx.get_attrs(item.def_id.to_def_id()).iter() {
if self.tcx.sess.check_name(attr, sym::rustc_layout) { if attr.has_name(sym::rustc_layout) {
self.dump_layout_of(item.def_id, item, attr); self.dump_layout_of(item.def_id, item, attr);
} }
} }

View File

@ -7,6 +7,7 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(crate_visibility_modifier)] #![feature(crate_visibility_modifier)]
#![feature(in_band_lifetimes)] #![feature(in_band_lifetimes)]
#![feature(format_args_capture)]
#![feature(iter_zip)] #![feature(iter_zip)]
#![feature(nll)] #![feature(nll)]
#![feature(min_specialization)] #![feature(min_specialization)]

View File

@ -33,9 +33,7 @@ impl LibFeatureCollector<'tcx> {
// Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`, // Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`,
// `#[rustc_const_unstable (..)]`). // `#[rustc_const_unstable (..)]`).
if let Some(stab_attr) = if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.has_name(**stab_attr)) {
stab_attrs.iter().find(|stab_attr| self.tcx.sess.check_name(attr, **stab_attr))
{
let meta_item = attr.meta(); let meta_item = attr.meta();
if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item { if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item {
let mut feature = None; let mut feature = None;

View File

@ -148,7 +148,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
} }
if self.tcx.features().staged_api { if self.tcx.features().staged_api {
if let Some(a) = attrs.iter().find(|a| self.tcx.sess.check_name(a, sym::deprecated)) { if let Some(a) = attrs.iter().find(|a| a.has_name(sym::deprecated)) {
self.tcx self.tcx
.sess .sess
.struct_span_err(a.span, "`#[deprecated]` cannot be used in staged API") .struct_span_err(a.span, "`#[deprecated]` cannot be used in staged API")
@ -350,7 +350,6 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
for attr in attrs { for attr in attrs {
let name = attr.name_or_empty(); let name = attr.name_or_empty();
if unstable_attrs.contains(&name) { if unstable_attrs.contains(&name) {
self.tcx.sess.mark_attr_used(attr);
struct_span_err!( struct_span_err!(
self.tcx.sess, self.tcx.sess,
attr.span, attr.span,

View File

@ -1,5 +1,6 @@
//! Validity checking for weak lang items //! Validity checking for weak lang items
use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err; use rustc_errors::struct_span_err;
use rustc_hir as hir; use rustc_hir as hir;
@ -96,7 +97,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
} }
fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) { fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym); let check_name = |attr: &Attribute, sym| attr.has_name(sym);
let attrs = self.tcx.hir().attrs(i.hir_id()); let attrs = self.tcx.hir().attrs(i.hir_id());
if let Some((lang_item, _)) = lang_items::extract(check_name, attrs) { if let Some((lang_item, _)) = lang_items::extract(check_name, attrs) {
self.register(lang_item, i.span); self.register(lang_item, i.span);

View File

@ -32,7 +32,7 @@ pub fn load_plugins(
let mut plugins = Vec::new(); let mut plugins = Vec::new();
for attr in &krate.attrs { for attr in &krate.attrs {
if !sess.check_name(attr, sym::plugin) { if !attr.has_name(sym::plugin) {
continue; continue;
} }

View File

@ -885,9 +885,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
// Non-opaque macros cannot make other items more accessible than they already are. // Non-opaque macros cannot make other items more accessible than they already are.
let attrs = self.tcx.hir().attrs(md.hir_id()); let attrs = self.tcx.hir().attrs(md.hir_id());
if attr::find_transparency(&self.tcx.sess, &attrs, md.ast.macro_rules).0 if attr::find_transparency(&attrs, md.ast.macro_rules).0 != Transparency::Opaque {
!= Transparency::Opaque
{
// `#[macro_export]`-ed `macro_rules!` are `Public` since they // `#[macro_export]`-ed `macro_rules!` are `Public` since they
// ignore their containing path to always appear at the crate root. // ignore their containing path to always appear at the crate root.
if md.ast.macro_rules { if md.ast.macro_rules {

View File

@ -1059,7 +1059,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
let mut import_all = None; let mut import_all = None;
let mut single_imports = Vec::new(); let mut single_imports = Vec::new();
for attr in &item.attrs { for attr in &item.attrs {
if self.r.session.check_name(attr, sym::macro_use) { if attr.has_name(sym::macro_use) {
if self.parent_scope.module.parent.is_some() { if self.parent_scope.module.parent.is_some() {
struct_span_err!( struct_span_err!(
self.r.session, self.r.session,
@ -1165,7 +1165,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
/// Returns `true` if this attribute list contains `macro_use`. /// Returns `true` if this attribute list contains `macro_use`.
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
for attr in attrs { for attr in attrs {
if self.r.session.check_name(attr, sym::macro_escape) { if attr.has_name(sym::macro_escape) {
let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`"; let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`";
let mut err = self.r.session.struct_span_warn(attr.span, msg); let mut err = self.r.session.struct_span_warn(attr.span, msg);
if let ast::AttrStyle::Inner = attr.style { if let ast::AttrStyle::Inner = attr.style {
@ -1173,7 +1173,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
} else { } else {
err.emit(); err.emit();
} }
} else if !self.r.session.check_name(attr, sym::macro_use) { } else if !attr.has_name(sym::macro_use) {
continue; continue;
} }

View File

@ -2057,9 +2057,13 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
if let Some(def_id) = parent_def_id.as_local() { if let Some(def_id) = parent_def_id.as_local() {
let parent_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let parent_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id);
// lifetimes in `derive` expansions don't count (Issue #53738) // lifetimes in `derive` expansions don't count (Issue #53738)
if self.tcx.hir().attrs(parent_hir_id).iter().any(|attr| { if self
self.tcx.sess.check_name(attr, sym::automatically_derived) .tcx
}) { .hir()
.attrs(parent_hir_id)
.iter()
.any(|attr| attr.has_name(sym::automatically_derived))
{
continue; continue;
} }
} }

View File

@ -3382,9 +3382,8 @@ impl<'a> Resolver<'a> {
let parse_attrs = || { let parse_attrs = || {
let attrs = self.cstore().item_attrs(def_id, self.session); let attrs = self.cstore().item_attrs(def_id, self.session);
let attr = attrs let attr =
.iter() attrs.iter().find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
.find(|a| self.session.check_name(a, sym::rustc_legacy_const_generics))?;
let mut ret = vec![]; let mut ret = vec![];
for meta in attr.meta_item_list()? { for meta in attr.meta_item_list()? {
match meta.literal()?.kind { match meta.literal()?.kind {

View File

@ -213,8 +213,6 @@ pub struct Session {
/// Set of enabled features for the current target. /// Set of enabled features for the current target.
pub target_features: FxHashSet<Symbol>, pub target_features: FxHashSet<Symbol>,
used_attrs: Lock<MarkedAttrs>,
/// `Span`s for `if` conditions that we have suggested turning into `if let`. /// `Span`s for `if` conditions that we have suggested turning into `if let`.
pub if_let_suggestions: Lock<FxHashSet<Span>>, pub if_let_suggestions: Lock<FxHashSet<Span>>,
} }
@ -1066,39 +1064,14 @@ impl Session {
== config::InstrumentCoverage::ExceptUnusedFunctions == config::InstrumentCoverage::ExceptUnusedFunctions
} }
pub fn mark_attr_used(&self, attr: &Attribute) {
self.used_attrs.lock().mark(attr)
}
pub fn is_attr_used(&self, attr: &Attribute) -> bool {
self.used_attrs.lock().is_marked(attr)
}
/// Returns `true` if the attribute's path matches the argument. If it
/// matches, then the attribute is marked as used.
///
/// This method should only be used by rustc, other tools can use
/// `Attribute::has_name` instead, because only rustc is supposed to report
/// the `unused_attributes` lint. (`MetaItem` and `NestedMetaItem` are
/// produced by lowering an `Attribute` and don't have identity, so they
/// only have the `has_name` method, and you need to mark the original
/// `Attribute` as used when necessary.)
pub fn check_name(&self, attr: &Attribute, name: Symbol) -> bool {
let matches = attr.has_name(name);
if matches {
self.mark_attr_used(attr);
}
matches
}
pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool { pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive] [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter() .iter()
.any(|kind| self.check_name(attr, *kind)) .any(|kind| attr.has_name(*kind))
} }
pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool { pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool {
attrs.iter().any(|item| self.check_name(item, name)) attrs.iter().any(|item| item.has_name(name))
} }
pub fn find_by_name<'a>( pub fn find_by_name<'a>(
@ -1106,7 +1079,7 @@ impl Session {
attrs: &'a [Attribute], attrs: &'a [Attribute],
name: Symbol, name: Symbol,
) -> Option<&'a Attribute> { ) -> Option<&'a Attribute> {
attrs.iter().find(|attr| self.check_name(attr, name)) attrs.iter().find(|attr| attr.has_name(name))
} }
pub fn filter_by_name<'a>( pub fn filter_by_name<'a>(
@ -1114,7 +1087,7 @@ impl Session {
attrs: &'a [Attribute], attrs: &'a [Attribute],
name: Symbol, name: Symbol,
) -> impl Iterator<Item = &'a Attribute> { ) -> impl Iterator<Item = &'a Attribute> {
attrs.iter().filter(move |attr| self.check_name(attr, name)) attrs.iter().filter(move |attr| attr.has_name(name))
} }
pub fn first_attr_value_str_by_name( pub fn first_attr_value_str_by_name(
@ -1122,7 +1095,7 @@ impl Session {
attrs: &[Attribute], attrs: &[Attribute],
name: Symbol, name: Symbol,
) -> Option<Symbol> { ) -> Option<Symbol> {
attrs.iter().find(|at| self.check_name(at, name)).and_then(|at| at.value_str()) attrs.iter().find(|at| at.has_name(name)).and_then(|at| at.value_str())
} }
} }
@ -1359,7 +1332,6 @@ pub fn build_session(
miri_unleashed_features: Lock::new(Default::default()), miri_unleashed_features: Lock::new(Default::default()),
asm_arch, asm_arch,
target_features: FxHashSet::default(), target_features: FxHashSet::default(),
used_attrs: Lock::new(MarkedAttrs::new()),
if_let_suggestions: Default::default(), if_let_suggestions: Default::default(),
}; };

View File

@ -35,7 +35,7 @@ impl SymbolNamesTest<'tcx> {
fn process_attrs(&mut self, def_id: LocalDefId) { fn process_attrs(&mut self, def_id: LocalDefId) {
let tcx = self.tcx; let tcx = self.tcx;
for attr in tcx.get_attrs(def_id.to_def_id()).iter() { for attr in tcx.get_attrs(def_id.to_def_id()).iter() {
if tcx.sess.check_name(attr, SYMBOL_NAME) { if attr.has_name(SYMBOL_NAME) {
let def_id = def_id.to_def_id(); let def_id = def_id.to_def_id();
let instance = Instance::new( let instance = Instance::new(
def_id, def_id,
@ -47,7 +47,7 @@ impl SymbolNamesTest<'tcx> {
tcx.sess.span_err(attr.span, &format!("demangling({})", demangling)); tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling)); tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
} }
} else if tcx.sess.check_name(attr, DEF_PATH) { } else if attr.has_name(DEF_PATH) {
let path = with_no_trimmed_paths(|| tcx.def_path_str(def_id.to_def_id())); let path = with_no_trimmed_paths(|| tcx.def_path_str(def_id.to_def_id()));
tcx.sess.span_err(attr.span, &format!("def-path({})", path)); tcx.sess.span_err(attr.span, &format!("def-path({})", path));
} }

View File

@ -257,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// //
// FIXME? Other potential candidate methods: `as_ref` and // FIXME? Other potential candidate methods: `as_ref` and
// `as_mut`? // `as_mut`?
.any(|a| self.sess().check_name(a, sym::rustc_conversion_suggestion)) .any(|a| a.has_name(sym::rustc_conversion_suggestion))
}); });
methods methods

View File

@ -21,6 +21,7 @@ use crate::constrained_generic_params as cgp;
use crate::errors; use crate::errors;
use crate::middle::resolve_lifetime as rl; use crate::middle::resolve_lifetime as rl;
use rustc_ast as ast; use rustc_ast as ast;
use rustc_ast::Attribute;
use rustc_ast::{MetaItemKind, NestedMetaItem}; use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures; use rustc_data_structures::captures::Captures;
@ -2769,11 +2770,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
let mut link_ordinal_span = None; let mut link_ordinal_span = None;
let mut no_sanitize_span = None; let mut no_sanitize_span = None;
for attr in attrs.iter() { for attr in attrs.iter() {
if tcx.sess.check_name(attr, sym::cold) { if attr.has_name(sym::cold) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD; codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
} else if tcx.sess.check_name(attr, sym::rustc_allocator) { } else if attr.has_name(sym::rustc_allocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR; codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
} else if tcx.sess.check_name(attr, sym::ffi_returns_twice) { } else if attr.has_name(sym::ffi_returns_twice) {
if tcx.is_foreign_item(id) { if tcx.is_foreign_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE; codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
} else { } else {
@ -2786,9 +2787,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
) )
.emit(); .emit();
} }
} else if tcx.sess.check_name(attr, sym::ffi_pure) { } else if attr.has_name(sym::ffi_pure) {
if tcx.is_foreign_item(id) { if tcx.is_foreign_item(id) {
if attrs.iter().any(|a| tcx.sess.check_name(a, sym::ffi_const)) { if attrs.iter().any(|a| a.has_name(sym::ffi_const)) {
// `#[ffi_const]` functions cannot be `#[ffi_pure]` // `#[ffi_const]` functions cannot be `#[ffi_pure]`
struct_span_err!( struct_span_err!(
tcx.sess, tcx.sess,
@ -2810,7 +2811,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
) )
.emit(); .emit();
} }
} else if tcx.sess.check_name(attr, sym::ffi_const) { } else if attr.has_name(sym::ffi_const) {
if tcx.is_foreign_item(id) { if tcx.is_foreign_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST; codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
} else { } else {
@ -2823,19 +2824,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
) )
.emit(); .emit();
} }
} else if tcx.sess.check_name(attr, sym::rustc_allocator_nounwind) { } else if attr.has_name(sym::rustc_allocator_nounwind) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND; codegen_fn_attrs.flags |= CodegenFnAttrFlags::NEVER_UNWIND;
} else if tcx.sess.check_name(attr, sym::naked) { } else if attr.has_name(sym::naked) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED; codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
} else if tcx.sess.check_name(attr, sym::no_mangle) { } else if attr.has_name(sym::no_mangle) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE; codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
} else if tcx.sess.check_name(attr, sym::no_coverage) { } else if attr.has_name(sym::no_coverage) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE; codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_COVERAGE;
} else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) { } else if attr.has_name(sym::rustc_std_internal_symbol) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
} else if tcx.sess.check_name(attr, sym::used) { } else if attr.has_name(sym::used) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
} else if tcx.sess.check_name(attr, sym::cmse_nonsecure_entry) { } else if attr.has_name(sym::cmse_nonsecure_entry) {
if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) { if !matches!(tcx.fn_sig(id).abi(), abi::Abi::C { .. }) {
struct_span_err!( struct_span_err!(
tcx.sess, tcx.sess,
@ -2850,15 +2851,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
.emit(); .emit();
} }
codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY; codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY;
} else if tcx.sess.check_name(attr, sym::thread_local) { } else if attr.has_name(sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
} else if tcx.sess.check_name(attr, sym::track_caller) { } else if attr.has_name(sym::track_caller) {
if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust { if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI") struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit(); .emit();
} }
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
} else if tcx.sess.check_name(attr, sym::export_name) { } else if attr.has_name(sym::export_name) {
if let Some(s) = attr.value_str() { if let Some(s) = attr.value_str() {
if s.as_str().contains('\0') { if s.as_str().contains('\0') {
// `#[export_name = ...]` will be converted to a null-terminated string, // `#[export_name = ...]` will be converted to a null-terminated string,
@ -2873,7 +2874,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
} }
codegen_fn_attrs.export_name = Some(s); codegen_fn_attrs.export_name = Some(s);
} }
} else if tcx.sess.check_name(attr, sym::target_feature) { } else if attr.has_name(sym::target_feature) {
if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal {
if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc { if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
// The `#[target_feature]` attribute is allowed on // The `#[target_feature]` attribute is allowed on
@ -2913,11 +2914,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
&supported_target_features, &supported_target_features,
&mut codegen_fn_attrs.target_features, &mut codegen_fn_attrs.target_features,
); );
} else if tcx.sess.check_name(attr, sym::linkage) { } else if attr.has_name(sym::linkage) {
if let Some(val) = attr.value_str() { if let Some(val) = attr.value_str() {
codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str())); codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str()));
} }
} else if tcx.sess.check_name(attr, sym::link_section) { } else if attr.has_name(sym::link_section) {
if let Some(val) = attr.value_str() { if let Some(val) = attr.value_str() {
if val.as_str().bytes().any(|b| b == 0) { if val.as_str().bytes().any(|b| b == 0) {
let msg = format!( let msg = format!(
@ -2930,14 +2931,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
codegen_fn_attrs.link_section = Some(val); codegen_fn_attrs.link_section = Some(val);
} }
} }
} else if tcx.sess.check_name(attr, sym::link_name) { } else if attr.has_name(sym::link_name) {
codegen_fn_attrs.link_name = attr.value_str(); codegen_fn_attrs.link_name = attr.value_str();
} else if tcx.sess.check_name(attr, sym::link_ordinal) { } else if attr.has_name(sym::link_ordinal) {
link_ordinal_span = Some(attr.span); link_ordinal_span = Some(attr.span);
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) { if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
codegen_fn_attrs.link_ordinal = ordinal; codegen_fn_attrs.link_ordinal = ordinal;
} }
} else if tcx.sess.check_name(attr, sym::no_sanitize) { } else if attr.has_name(sym::no_sanitize) {
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() {
@ -2957,7 +2958,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
} }
} }
} }
} else if tcx.sess.check_name(attr, sym::instruction_set) { } else if attr.has_name(sym::instruction_set) {
codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) { codegen_fn_attrs.instruction_set = match attr.meta().map(|i| i.kind) {
Some(MetaItemKind::List(ref items)) => match items.as_slice() { Some(MetaItemKind::List(ref items)) => match items.as_slice() {
[NestedMetaItem::MetaItem(set)] => { [NestedMetaItem::MetaItem(set)] => {
@ -3026,7 +3027,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
None None
} }
}; };
} else if tcx.sess.check_name(attr, sym::repr) { } else if attr.has_name(sym::repr) {
codegen_fn_attrs.alignment = match attr.meta_item_list() { codegen_fn_attrs.alignment = match attr.meta_item_list() {
Some(items) => match items.as_slice() { Some(items) => match items.as_slice() {
[item] => match item.name_value_literal() { [item] => match item.name_value_literal() {
@ -3064,12 +3065,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
return ia; return ia;
} }
match attr.meta().map(|i| i.kind) { match attr.meta().map(|i| i.kind) {
Some(MetaItemKind::Word) => { Some(MetaItemKind::Word) => InlineAttr::Hint,
tcx.sess.mark_attr_used(attr);
InlineAttr::Hint
}
Some(MetaItemKind::List(ref items)) => { Some(MetaItemKind::List(ref items)) => {
tcx.sess.mark_attr_used(attr);
inline_span = Some(attr.span); inline_span = Some(attr.span);
if items.len() != 1 { if items.len() != 1 {
struct_span_err!( struct_span_err!(
@ -3112,7 +3109,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
ia ia
} }
Some(MetaItemKind::List(ref items)) => { Some(MetaItemKind::List(ref items)) => {
tcx.sess.mark_attr_used(attr);
inline_span = Some(attr.span); inline_span = Some(attr.span);
if items.len() != 1 { if items.len() != 1 {
err(attr.span, "expected one argument"); err(attr.span, "expected one argument");
@ -3181,7 +3177,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
if tcx.is_weak_lang_item(id) { if tcx.is_weak_lang_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
} }
let check_name = |attr, sym| tcx.sess.check_name(attr, sym); let check_name = |attr: &Attribute, sym| attr.has_name(sym);
if let Some(name) = weak_lang_items::link_name(check_name, &attrs) { if let Some(name) = weak_lang_items::link_name(check_name, &attrs) {
codegen_fn_attrs.export_name = Some(name); codegen_fn_attrs.export_name = Some(name);
codegen_fn_attrs.link_name = Some(name); codegen_fn_attrs.link_name = Some(name);

View File

@ -291,7 +291,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) {
} }
for attr in tcx.get_attrs(main_def_id) { for attr in tcx.get_attrs(main_def_id) {
if tcx.sess.check_name(attr, sym::track_caller) { if attr.has_name(sym::track_caller) {
tcx.sess tcx.sess
.struct_span_err( .struct_span_err(
attr.span, attr.span,
@ -405,7 +405,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
let attrs = tcx.hir().attrs(start_id); let attrs = tcx.hir().attrs(start_id);
for attr in attrs { for attr in attrs {
if tcx.sess.check_name(attr, sym::track_caller) { if attr.has_name(sym::track_caller) {
tcx.sess tcx.sess
.struct_span_err( .struct_span_err(
attr.span, attr.span,

View File

@ -4,7 +4,5 @@
#![feature(register_tool)] #![feature(register_tool)]
#[register_attr(attr)] //~ ERROR crate-level attribute should be an inner attribute #[register_attr(attr)] //~ ERROR crate-level attribute should be an inner attribute
//~| ERROR unused attribute
#[register_tool(tool)] //~ ERROR crate-level attribute should be an inner attribute #[register_tool(tool)] //~ ERROR crate-level attribute should be an inner attribute
//~| ERROR unused attribute
fn main() {} fn main() {}

View File

@ -1,4 +1,4 @@
error: unused attribute error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
--> $DIR/register-attr-tool-unused.rs:6:1 --> $DIR/register-attr-tool-unused.rs:6:1
| |
LL | #[register_attr(attr)] LL | #[register_attr(attr)]
@ -12,22 +12,10 @@ LL | #![deny(unused)]
= note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]`
error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
--> $DIR/register-attr-tool-unused.rs:6:1 --> $DIR/register-attr-tool-unused.rs:7:1
|
LL | #[register_attr(attr)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/register-attr-tool-unused.rs:8:1
| |
LL | #[register_tool(tool)] LL | #[register_tool(tool)]
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` error: aborting due to 2 previous errors
--> $DIR/register-attr-tool-unused.rs:8:1
|
LL | #[register_tool(tool)]
| ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors

View File

@ -4,10 +4,10 @@
#![deny(unused)] #![deny(unused)]
#[cfg_attr(FALSE,)] //~ ERROR unused attribute #[cfg_attr(FALSE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes
fn _f() {} fn _f() {}
#[cfg_attr(TRUE,)] //~ ERROR unused attribute #[cfg_attr(TRUE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes
fn _g() {} fn _g() {}
fn main() {} fn main() {}

View File

@ -1,4 +1,4 @@
error: unused attribute error: `#[cfg_attr]` does not expand to any attributes
--> $DIR/cfg-attr-empty-is-unused.rs:7:1 --> $DIR/cfg-attr-empty-is-unused.rs:7:1
| |
LL | #[cfg_attr(FALSE,)] LL | #[cfg_attr(FALSE,)]
@ -11,7 +11,7 @@ LL | #![deny(unused)]
| ^^^^^^ | ^^^^^^
= note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]` = note: `#[deny(unused_attributes)]` implied by `#[deny(unused)]`
error: unused attribute error: `#[cfg_attr]` does not expand to any attributes
--> $DIR/cfg-attr-empty-is-unused.rs:10:1 --> $DIR/cfg-attr-empty-is-unused.rs:10:1
| |
LL | #[cfg_attr(TRUE,)] LL | #[cfg_attr(TRUE,)]

View File

@ -13,7 +13,6 @@ pub struct ConstDefaultUnstable<const N: usize = 3>;
#[stable(feature = "const_default_unstable", since="none")] #[stable(feature = "const_default_unstable", since="none")]
pub struct ConstDefaultStable<const N: usize = { pub struct ConstDefaultStable<const N: usize = {
#[stable(feature = "const_default_unstable_val", since="none")]
3 3
}>; }>;

View File

@ -49,14 +49,14 @@
#![macro_use] // (allowed if no argument; see issue-43160-gating-of-macro_use.rs) #![macro_use] // (allowed if no argument; see issue-43160-gating-of-macro_use.rs)
// skipping testing of cfg // skipping testing of cfg
// skipping testing of cfg_attr // skipping testing of cfg_attr
#![should_panic] //~ WARN unused attribute #![should_panic] //~ WARN `#[should_panic]` only has an effect
#![ignore] //~ WARN unused attribute #![ignore] //~ WARN `#[ignore]` only has an effect on functions
#![no_implicit_prelude] #![no_implicit_prelude]
#![reexport_test_harness_main = "2900"] #![reexport_test_harness_main = "2900"]
// see gated-link-args.rs // see gated-link-args.rs
// see issue-43106-gating-of-macro_escape.rs for crate-level; but non crate-level is below at "2700" // see issue-43106-gating-of-macro_escape.rs for crate-level; but non crate-level is below at "2700"
// (cannot easily test gating of crate-level #[no_std]; but non crate-level is below at "2600") // (cannot easily test gating of crate-level #[no_std]; but non crate-level is below at "2600")
#![proc_macro_derive()] //~ WARN unused attribute #![proc_macro_derive()] //~ WARN `#[proc_macro_derive]` only has an effect
#![doc = "2400"] #![doc = "2400"]
#![cold] //~ WARN attribute should be applied to a function #![cold] //~ WARN attribute should be applied to a function
//~^ WARN //~^ WARN
@ -182,35 +182,35 @@ mod macro_use {
mod inner { #![macro_use] } mod inner { #![macro_use] }
#[macro_use] fn f() { } #[macro_use] fn f() { }
//~^ WARN unused attribute //~^ `#[macro_use]` only has an effect
#[macro_use] struct S; #[macro_use] struct S;
//~^ WARN unused attribute //~^ `#[macro_use]` only has an effect
#[macro_use] type T = S; #[macro_use] type T = S;
//~^ WARN unused attribute //~^ `#[macro_use]` only has an effect
#[macro_use] impl S { } #[macro_use] impl S { }
//~^ WARN unused attribute //~^ `#[macro_use]` only has an effect
} }
#[macro_export] #[macro_export]
//~^ WARN unused attribute //~^ WARN `#[macro_export]` only has an effect on macro definitions
mod macro_export { mod macro_export {
mod inner { #![macro_export] } mod inner { #![macro_export] }
//~^ WARN unused attribute //~^ WARN `#[macro_export]` only has an effect on macro definitions
#[macro_export] fn f() { } #[macro_export] fn f() { }
//~^ WARN unused attribute //~^ WARN `#[macro_export]` only has an effect on macro definitions
#[macro_export] struct S; #[macro_export] struct S;
//~^ WARN unused attribute //~^ WARN `#[macro_export]` only has an effect on macro definitions
#[macro_export] type T = S; #[macro_export] type T = S;
//~^ WARN unused attribute //~^ WARN `#[macro_export]` only has an effect on macro definitions
#[macro_export] impl S { } #[macro_export] impl S { }
//~^ WARN unused attribute //~^ WARN `#[macro_export]` only has an effect on macro definitions
} }
// At time of unit test authorship, if compiling without `--test` then // At time of unit test authorship, if compiling without `--test` then
@ -263,35 +263,32 @@ mod path {
mod inner { #![path="3800"] } mod inner { #![path="3800"] }
#[path = "3800"] fn f() { } #[path = "3800"] fn f() { }
//~^ WARN unused attribute //~^ WARN `#[path]` only has an effect
#[path = "3800"] struct S; #[path = "3800"] struct S;
//~^ WARN unused attribute //~^ WARN `#[path]` only has an effect
#[path = "3800"] type T = S; #[path = "3800"] type T = S;
//~^ WARN unused attribute //~^ WARN `#[path]` only has an effect
#[path = "3800"] impl S { } #[path = "3800"] impl S { }
//~^ WARN unused attribute //~^ WARN `#[path]` only has an effect
} }
// Don't warn on `automatically_derived` - a custom derive
// could reasonally annotate anything that it emits with
// this attribute
#[automatically_derived] #[automatically_derived]
//~^ WARN unused attribute
mod automatically_derived { mod automatically_derived {
mod inner { #![automatically_derived] } mod inner { #![automatically_derived] }
//~^ WARN unused attribute
#[automatically_derived] fn f() { } #[automatically_derived] fn f() { }
//~^ WARN unused attribute
#[automatically_derived] struct S; #[automatically_derived] struct S;
//~^ WARN unused attribute
#[automatically_derived] type T = S; #[automatically_derived] type T = S;
//~^ WARN unused attribute
#[automatically_derived] impl S { } #[automatically_derived] impl S { }
//~^ WARN unused attribute
} }
#[no_mangle] #[no_mangle]
@ -335,79 +332,77 @@ mod no_mangle {
} }
#[should_panic] #[should_panic]
//~^ WARN unused attribute //~^ WARN `#[should_panic]` only has an effect on
mod should_panic { mod should_panic {
mod inner { #![should_panic] } mod inner { #![should_panic] }
//~^ WARN unused attribute //~^ WARN `#[should_panic]` only has an effect on
#[should_panic] fn f() { } #[should_panic] fn f() { }
//~^ WARN unused attribute
#[should_panic] struct S; #[should_panic] struct S;
//~^ WARN unused attribute //~^ WARN `#[should_panic]` only has an effect on
#[should_panic] type T = S; #[should_panic] type T = S;
//~^ WARN unused attribute //~^ WARN `#[should_panic]` only has an effect on
#[should_panic] impl S { } #[should_panic] impl S { }
//~^ WARN unused attribute //~^ WARN `#[should_panic]` only has an effect on
} }
#[ignore] #[ignore]
//~^ WARN unused attribute //~^ WARN `#[ignore]` only has an effect on functions
mod ignore { mod ignore {
mod inner { #![ignore] } mod inner { #![ignore] }
//~^ WARN unused attribute //~^ WARN `#[ignore]` only has an effect on functions
#[ignore] fn f() { } #[ignore] fn f() { }
//~^ WARN unused attribute
#[ignore] struct S; #[ignore] struct S;
//~^ WARN unused attribute //~^ WARN `#[ignore]` only has an effect on functions
#[ignore] type T = S; #[ignore] type T = S;
//~^ WARN unused attribute //~^ WARN `#[ignore]` only has an effect on functions
#[ignore] impl S { } #[ignore] impl S { }
//~^ WARN unused attribute //~^ WARN `#[ignore]` only has an effect on functions
} }
#[no_implicit_prelude] #[no_implicit_prelude]
//~^ WARN unused attribute //~^ WARN crate-level attribute
mod no_implicit_prelude { mod no_implicit_prelude {
mod inner { #![no_implicit_prelude] } mod inner { #![no_implicit_prelude] }
//~^ WARN unused attribute //~^ WARN crate-level attribute
#[no_implicit_prelude] fn f() { } #[no_implicit_prelude] fn f() { }
//~^ WARN unused attribute //~^ WARN crate-level attribute
#[no_implicit_prelude] struct S; #[no_implicit_prelude] struct S;
//~^ WARN unused attribute //~^ WARN crate-level attribute
#[no_implicit_prelude] type T = S; #[no_implicit_prelude] type T = S;
//~^ WARN unused attribute //~^ WARN crate-level attribute
#[no_implicit_prelude] impl S { } #[no_implicit_prelude] impl S { }
//~^ WARN unused attribute //~^ WARN crate-level attribute
} }
#[reexport_test_harness_main = "2900"] #[reexport_test_harness_main = "2900"]
//~^ WARN unused attribute //~^ WARN crate-level attribute should be
mod reexport_test_harness_main { mod reexport_test_harness_main {
mod inner { #![reexport_test_harness_main="2900"] } mod inner { #![reexport_test_harness_main="2900"] }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be
#[reexport_test_harness_main = "2900"] fn f() { } #[reexport_test_harness_main = "2900"] fn f() { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be
#[reexport_test_harness_main = "2900"] struct S; #[reexport_test_harness_main = "2900"] struct S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be
#[reexport_test_harness_main = "2900"] type T = S; #[reexport_test_harness_main = "2900"] type T = S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be
#[reexport_test_harness_main = "2900"] impl S { } #[reexport_test_harness_main = "2900"] impl S { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be
} }
// Cannot feed "2700" to `#[macro_escape]` without signaling an error. // Cannot feed "2700" to `#[macro_escape]` without signaling an error.
@ -419,41 +414,35 @@ mod macro_escape {
//~| HELP try an outer attribute: `#[macro_use]` //~| HELP try an outer attribute: `#[macro_use]`
#[macro_escape] fn f() { } #[macro_escape] fn f() { }
//~^ WARN unused attribute //~^ WARN `#[macro_escape]` only has an effect
#[macro_escape] struct S; #[macro_escape] struct S;
//~^ WARN unused attribute //~^ WARN `#[macro_escape]` only has an effect
#[macro_escape] type T = S; #[macro_escape] type T = S;
//~^ WARN unused attribute //~^ WARN `#[macro_escape]` only has an effect
#[macro_escape] impl S { } #[macro_escape] impl S { }
//~^ WARN unused attribute //~^ WARN `#[macro_escape]` only has an effect
} }
#[no_std] #[no_std]
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
mod no_std { mod no_std {
mod inner { #![no_std] } mod inner { #![no_std] }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be in the root module
//~| WARN crate-level attribute should be in the root module
#[no_std] fn f() { } #[no_std] fn f() { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[no_std] struct S; #[no_std] struct S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[no_std] type T = S; #[no_std] type T = S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[no_std] impl S { } #[no_std] impl S { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
} }
// At time of authorship, #[proc_macro_derive = "2500"] signals error // At time of authorship, #[proc_macro_derive = "2500"] signals error
@ -633,104 +622,80 @@ mod windows_subsystem {
// BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES // BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES
#[crate_name = "0900"] #[crate_name = "0900"]
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
mod crate_name { mod crate_name {
mod inner { #![crate_name="0900"] } mod inner { #![crate_name="0900"] }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be in the root module
//~| WARN crate-level attribute should be in the root module
#[crate_name = "0900"] fn f() { } #[crate_name = "0900"] fn f() { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[crate_name = "0900"] struct S; #[crate_name = "0900"] struct S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[crate_name = "0900"] type T = S; #[crate_name = "0900"] type T = S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[crate_name = "0900"] impl S { } #[crate_name = "0900"] impl S { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
} }
#[crate_type = "0800"] #[crate_type = "0800"]
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
mod crate_type { mod crate_type {
mod inner { #![crate_type="0800"] } mod inner { #![crate_type="0800"] }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be in the root module
//~| WARN crate-level attribute should be in the root module
#[crate_type = "0800"] fn f() { } #[crate_type = "0800"] fn f() { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[crate_type = "0800"] struct S; #[crate_type = "0800"] struct S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[crate_type = "0800"] type T = S; #[crate_type = "0800"] type T = S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[crate_type = "0800"] impl S { } #[crate_type = "0800"] impl S { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
} }
#[feature(x0600)] #[feature(x0600)]
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
mod feature { mod feature {
mod inner { #![feature(x0600)] } mod inner { #![feature(x0600)] }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be in the root module
//~| WARN crate-level attribute should be in the root module
#[feature(x0600)] fn f() { } #[feature(x0600)] fn f() { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[feature(x0600)] struct S; #[feature(x0600)] struct S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[feature(x0600)] type T = S; #[feature(x0600)] type T = S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[feature(x0600)] impl S { } #[feature(x0600)] impl S { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
} }
#[no_main] #[no_main]
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
mod no_main_1 { mod no_main_1 {
mod inner { #![no_main] } mod inner { #![no_main] }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be in the root module
//~| WARN crate-level attribute should be in the root module
#[no_main] fn f() { } #[no_main] fn f() { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[no_main] struct S; #[no_main] struct S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[no_main] type T = S; #[no_main] type T = S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[no_main] impl S { } #[no_main] impl S { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
} }
#[no_builtins] #[no_builtins]
@ -747,53 +712,41 @@ mod no_builtins {
} }
#[recursion_limit="0200"] #[recursion_limit="0200"]
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
mod recursion_limit { mod recursion_limit {
mod inner { #![recursion_limit="0200"] } mod inner { #![recursion_limit="0200"] }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be in the root module
//~| WARN crate-level attribute should be in the root module
#[recursion_limit="0200"] fn f() { } #[recursion_limit="0200"] fn f() { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[recursion_limit="0200"] struct S; #[recursion_limit="0200"] struct S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[recursion_limit="0200"] type T = S; #[recursion_limit="0200"] type T = S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[recursion_limit="0200"] impl S { } #[recursion_limit="0200"] impl S { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
} }
#[type_length_limit="0100"] #[type_length_limit="0100"]
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
mod type_length_limit { mod type_length_limit {
mod inner { #![type_length_limit="0100"] } mod inner { #![type_length_limit="0100"] }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be in the root module
//~| WARN crate-level attribute should be in the root module
#[type_length_limit="0100"] fn f() { } #[type_length_limit="0100"] fn f() { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[type_length_limit="0100"] struct S; #[type_length_limit="0100"] struct S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[type_length_limit="0100"] type T = S; #[type_length_limit="0100"] type T = S;
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
#[type_length_limit="0100"] impl S { } #[type_length_limit="0100"] impl S { }
//~^ WARN unused attribute //~^ WARN crate-level attribute should be an inner attribute
//~| WARN crate-level attribute should be an inner attribute
} }
fn main() {} fn main() {}

View File

@ -1,8 +1,7 @@
#![deny(unused_attributes)] #![deny(unused_attributes)]
#![feature(plugin)] #![feature(plugin)]
#[plugin(bla)] //~ ERROR unused attribute #[plugin(bla)] //~ ERROR should be an inner attribute
//~^ ERROR should be an inner attribute
//~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated //~| WARN use of deprecated attribute `plugin`: compiler plugins are deprecated
fn main() {} fn main() {}

View File

@ -6,7 +6,7 @@ LL | #[plugin(bla)]
| |
= note: `#[warn(deprecated)]` on by default = note: `#[warn(deprecated)]` on by default
error: unused attribute error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
--> $DIR/invalid-plugin-attr.rs:4:1 --> $DIR/invalid-plugin-attr.rs:4:1
| |
LL | #[plugin(bla)] LL | #[plugin(bla)]
@ -18,11 +18,5 @@ note: the lint level is defined here
LL | #![deny(unused_attributes)] LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` error: aborting due to previous error; 1 warning emitted
--> $DIR/invalid-plugin-attr.rs:4:1
|
LL | #[plugin(bla)]
| ^^^^^^^^^^^^^^
error: aborting due to 2 previous errors; 1 warning emitted

View File

@ -4,9 +4,7 @@
#![deny(unused_attributes)] #![deny(unused_attributes)]
mod a { mod a {
#![crate_type = "bin"] //~ ERROR unused attribute #![crate_type = "bin"] //~ ERROR should be in the root module
//~^ ERROR should be in the root module
} }
#[crate_type = "bin"] fn main() {} //~ ERROR unused attribute #[crate_type = "bin"] fn main() {} //~ ERROR should be an inner
//~^ ERROR should be an inner

View File

@ -1,4 +1,4 @@
error: unused attribute error: crate-level attribute should be in the root module
--> $DIR/lint-misplaced-attr.rs:7:5 --> $DIR/lint-misplaced-attr.rs:7:5
| |
LL | #![crate_type = "bin"] LL | #![crate_type = "bin"]
@ -10,23 +10,11 @@ note: the lint level is defined here
LL | #![deny(unused_attributes)] LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: crate-level attribute should be in the root module
--> $DIR/lint-misplaced-attr.rs:7:5
|
LL | #![crate_type = "bin"]
| ^^^^^^^^^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/lint-misplaced-attr.rs:11:1
|
LL | #[crate_type = "bin"] fn main() {}
| ^^^^^^^^^^^^^^^^^^^^^
error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
--> $DIR/lint-misplaced-attr.rs:11:1 --> $DIR/lint-misplaced-attr.rs:10:1
| |
LL | #[crate_type = "bin"] fn main() {} LL | #[crate_type = "bin"] fn main() {}
| ^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors error: aborting due to 2 previous errors

View File

@ -4,10 +4,9 @@
// A sample of various built-in attributes. // A sample of various built-in attributes.
#[macro_export] #[macro_export]
#[macro_use] //~ ERROR unused attribute #[macro_use] //~ ERROR `#[macro_use]` only has an effect
#[path="foo"] //~ ERROR unused attribute #[path="foo"] //~ ERROR #[path]` only has an effect
#[recursion_limit="1"] //~ ERROR unused attribute #[recursion_limit="1"] //~ ERROR crate-level attribute should be an inner attribute
//~| ERROR crate-level attribute should be an inner attribute
macro_rules! foo { macro_rules! foo {
() => {}; () => {};
} }

View File

@ -1,4 +1,4 @@
error: unused attribute error: `#[macro_use]` only has an effect on `extern crate` and modules
--> $DIR/unused-attr-macro-rules.rs:7:1 --> $DIR/unused-attr-macro-rules.rs:7:1
| |
LL | #[macro_use] LL | #[macro_use]
@ -10,23 +10,17 @@ note: the lint level is defined here
LL | #![deny(unused_attributes)] LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^
error: unused attribute error: `#[path]` only has an effect on modules
--> $DIR/unused-attr-macro-rules.rs:8:1 --> $DIR/unused-attr-macro-rules.rs:8:1
| |
LL | #[path="foo"] LL | #[path="foo"]
| ^^^^^^^^^^^^^ | ^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr-macro-rules.rs:9:1
|
LL | #[recursion_limit="1"]
| ^^^^^^^^^^^^^^^^^^^^^^
error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` error: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
--> $DIR/unused-attr-macro-rules.rs:9:1 --> $DIR/unused-attr-macro-rules.rs:9:1
| |
LL | #[recursion_limit="1"] LL | #[recursion_limit="1"]
| ^^^^^^^^^^^^^^^^^^^^^^ | ^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 4 previous errors error: aborting due to 3 previous errors

View File

@ -1,49 +0,0 @@
#![deny(unused_attributes)]
#![feature(rustc_attrs)]
#![rustc_dummy] //~ ERROR unused attribute
#[rustc_dummy] //~ ERROR unused attribute
extern crate core;
#[rustc_dummy] //~ ERROR unused attribute
use std::collections;
#[rustc_dummy] //~ ERROR unused attribute
extern "C" {
#[rustc_dummy] //~ ERROR unused attribute
fn foo();
}
#[rustc_dummy] //~ ERROR unused attribute
mod foo {
#[rustc_dummy] //~ ERROR unused attribute
pub enum Foo {
#[rustc_dummy] //~ ERROR unused attribute
Bar,
}
}
#[rustc_dummy] //~ ERROR unused attribute
fn bar(f: foo::Foo) {
match f {
#[rustc_dummy] //~ ERROR unused attribute
foo::Foo::Bar => {}
}
}
#[rustc_dummy] //~ ERROR unused attribute
struct Foo {
#[rustc_dummy] //~ ERROR unused attribute
a: isize
}
#[rustc_dummy] //~ ERROR unused attribute
trait Baz {
#[rustc_dummy] //~ ERROR unused attribute
fn blah(&self);
#[rustc_dummy] //~ ERROR unused attribute
fn blah2(&self) {}
}
fn main() {}

View File

@ -1,98 +0,0 @@
error: unused attribute
--> $DIR/unused-attr.rs:4:1
|
LL | #![rustc_dummy]
| ^^^^^^^^^^^^^^^
|
note: the lint level is defined here
--> $DIR/unused-attr.rs:1:9
|
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:6:1
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:9:1
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:12:1
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:14:5
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:18:1
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:20:5
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:22:9
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:27:1
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:30:9
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:35:1
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:37:5
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:41:1
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:43:5
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: unused attribute
--> $DIR/unused-attr.rs:45:5
|
LL | #[rustc_dummy]
| ^^^^^^^^^^^^^^
error: aborting due to 15 previous errors