Auto merge of #87739 - Aaron1011:remove-used-attrs, r=wesleywiser

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:
bors 2021-08-24 03:58:22 +00:00
commit f66e825f73
64 changed files with 1109 additions and 1598 deletions

View File

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

View File

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

View File

@ -268,7 +268,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
gate_feature_fn!(self, has_feature, attr.span, name, descr);
}
// 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() {
macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
$(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
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() {
if nested_meta.has_name(sym::modifiers) {
gate_feature_post!(
@ -709,7 +709,7 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
if !sess.opts.unstable_features.is_nightly_build() {
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!(
sess.parse_sess.span_diagnostic,
attr.span,

View File

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

View File

@ -677,8 +677,6 @@ impl<'a> TraitDef<'a> {
let self_type = cx.ty_path(path);
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 unused_qual = {
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;
}
if self.sess.check_name(attr, sym::proc_macro_derive) {
if attr.has_name(sym::proc_macro_derive) {
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);
} else if self.sess.check_name(attr, sym::proc_macro) {
} else if attr.has_name(sym::proc_macro) {
self.collect_bang_proc_macro(item);
};

View File

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

View File

@ -654,10 +654,7 @@ pub enum SyntaxExtensionKind {
/// A trivial attribute "macro" that does nothing,
/// only keeps the attribute and marks it as inert,
/// thus making it ineligible for further expansion.
NonMacroAttr {
/// Suppresses the `unused_attributes` lint for this attribute.
mark_used: bool,
},
NonMacroAttr,
/// A token-based derive macro.
Derive(
@ -706,7 +703,7 @@ impl SyntaxExtension {
SyntaxExtensionKind::Bang(..) | SyntaxExtensionKind::LegacyBang(..) => MacroKind::Bang,
SyntaxExtensionKind::Attr(..)
| SyntaxExtensionKind::LegacyAttr(..)
| SyntaxExtensionKind::NonMacroAttr { .. } => MacroKind::Attr,
| SyntaxExtensionKind::NonMacroAttr => MacroKind::Attr,
SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => {
MacroKind::Derive
}
@ -812,8 +809,8 @@ impl SyntaxExtension {
SyntaxExtension::default(SyntaxExtensionKind::Derive(Box::new(expander)), edition)
}
pub fn non_macro_attr(mark_used: bool, edition: Edition) -> SyntaxExtension {
SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition)
pub fn non_macro_attr(edition: Edition) -> SyntaxExtension {
SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr, edition)
}
pub fn expn_data(

View File

@ -5,7 +5,7 @@ use rustc_ast::token::{DelimToken, Token, TokenKind};
use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
use rustc_ast::tokenstream::{DelimSpan, Spacing};
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_data_structures::fx::FxHashMap;
use rustc_data_structures::map_in_place::MapInPlace;
@ -14,7 +14,7 @@ use rustc_feature::{Feature, Features, State as FeatureState};
use rustc_feature::{
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::Session;
use rustc_span::edition::{Edition, ALL_EDITIONS};
@ -75,7 +75,7 @@ fn get_features(
// Process the edition umbrella feature-gates first, to ensure
// `edition_enabled_features` is completed before it's queried.
for attr in krate_attrs {
if !sess.check_name(attr, sym::feature) {
if !attr.has_name(sym::feature) {
continue;
}
@ -108,7 +108,7 @@ fn get_features(
}
for attr in krate_attrs {
if !sess.check_name(attr, sym::feature) {
if !attr.has_name(sym::feature) {
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> {
pub fn configure<T: AstLike>(&mut self, mut node: T) -> Option<T> {
self.process_cfg_attrs(&mut node);
@ -349,19 +344,17 @@ impl<'a> StripUnconfigured<'a> {
return vec![attr];
}
let (cfg_predicate, expanded_attrs) = match self.parse_cfg_attr(&attr) {
None => return vec![],
Some(r) => r,
};
let (cfg_predicate, expanded_attrs) =
match rustc_parse::parse_cfg_attr(&attr, &self.sess.parse_sess) {
None => return vec![],
Some(r) => r,
};
// Lint on zero attributes in source.
if expanded_attrs.is_empty() {
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) {
return vec![];
}
@ -415,46 +408,10 @@ impl<'a> StripUnconfigured<'a> {
.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.
fn in_cfg(&self, attrs: &[Attribute]) -> bool {
attrs.iter().all(|attr| {
if !is_cfg(self.sess, attr) {
if !is_cfg(attr) {
return true;
}
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
// 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";
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 {
sess.check_name(attr, sym::cfg)
fn is_cfg(attr: &Attribute) -> bool {
attr.has_name(sym::cfg)
}

View File

@ -753,11 +753,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
}
}
}
SyntaxExtensionKind::NonMacroAttr { mark_used } => {
SyntaxExtensionKind::NonMacroAttr => {
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));
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);
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 {
Some(TransparencyError::UnknownTransparency(value, span)) => {
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
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
CrateLevel,
}
@ -186,7 +181,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
),
// 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:
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!(forbid, 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)
ungated!(
deprecated, Normal,
@ -224,16 +219,16 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ABI, linking, symbols, and FFI
ungated!(
link, AssumedUsed,
link, Normal,
template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...""#),
),
ungated!(link_name, AssumedUsed, template!(NameValueStr: "name")),
ungated!(no_link, AssumedUsed, template!(Word)),
ungated!(repr, AssumedUsed, template!(List: "C")),
ungated!(export_name, AssumedUsed, template!(NameValueStr: "name")),
ungated!(link_section, AssumedUsed, template!(NameValueStr: "name")),
ungated!(no_mangle, AssumedUsed, template!(Word)),
ungated!(used, AssumedUsed, template!(Word)),
ungated!(link_name, Normal, template!(NameValueStr: "name")),
ungated!(no_link, Normal, template!(Word)),
ungated!(repr, Normal, template!(List: "C")),
ungated!(export_name, Normal, template!(NameValueStr: "name")),
ungated!(link_section, Normal, template!(NameValueStr: "name")),
ungated!(no_mangle, Normal, template!(Word)),
ungated!(used, Normal, template!(Word)),
// Limits:
ungated!(recursion_limit, CrateLevel, template!(NameValueStr: "N")),
@ -257,36 +252,36 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
ungated!(path, Normal, template!(NameValueStr: "file")),
ungated!(no_std, CrateLevel, template!(Word)),
ungated!(no_implicit_prelude, Normal, template!(Word)),
ungated!(non_exhaustive, AssumedUsed, template!(Word)),
ungated!(non_exhaustive, Normal, template!(Word)),
// 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
// Code generation:
ungated!(inline, AssumedUsed, template!(Word, List: "always|never")),
ungated!(cold, AssumedUsed, template!(Word)),
ungated!(no_builtins, AssumedUsed, template!(Word)),
ungated!(target_feature, AssumedUsed, template!(List: r#"enable = "name""#)),
ungated!(track_caller, AssumedUsed, template!(Word)),
ungated!(inline, Normal, template!(Word, List: "always|never")),
ungated!(cold, Normal, template!(Word)),
ungated!(no_builtins, Normal, template!(Word)),
ungated!(target_feature, Normal, template!(List: r#"enable = "name""#)),
ungated!(track_caller, Normal, template!(Word)),
gated!(
no_sanitize, AssumedUsed,
no_sanitize, Normal,
template!(List: "address, memory, thread"),
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.
ungated!(doc, AssumedUsed, template!(List: "hidden|inline|...", NameValueStr: "string")),
ungated!(doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string")),
// ==========================================================================
// Unstable attributes:
// ==========================================================================
// Linking:
gated!(naked, AssumedUsed, template!(Word), naked_functions, experimental!(naked)),
gated!(naked, Normal, template!(Word), naked_functions, experimental!(naked)),
gated!(
link_ordinal, AssumedUsed, template!(List: "ordinal"), raw_dylib,
link_ordinal, Normal, template!(List: "ordinal"), raw_dylib,
experimental!(link_ordinal)
),
@ -311,23 +306,23 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"custom test frameworks are an unstable feature",
),
// RFC #1268
gated!(marker, AssumedUsed, template!(Word), marker_trait_attr, experimental!(marker)),
gated!(marker, Normal, template!(Word), marker_trait_attr, experimental!(marker)),
gated!(
thread_local, AssumedUsed, template!(Word),
thread_local, Normal, template!(Word),
"`#[thread_local]` is an experimental feature, and does not currently handle destructors",
),
gated!(no_core, CrateLevel, template!(Word), experimental!(no_core)),
// RFC 2412
gated!(
optimize, AssumedUsed, template!(List: "size|speed"), optimize_attribute,
optimize, Normal, template!(List: "size|speed"), optimize_attribute,
experimental!(optimize),
),
// 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_pure, AssumedUsed, template!(Word), experimental!(ffi_pure)),
gated!(ffi_const, AssumedUsed, template!(Word), experimental!(ffi_const)),
gated!(ffi_returns_twice, Normal, template!(Word), experimental!(ffi_returns_twice)),
gated!(ffi_pure, Normal, template!(Word), experimental!(ffi_pure)),
gated!(ffi_const, Normal, template!(Word), experimental!(ffi_const)),
gated!(
register_attr, CrateLevel, template!(List: "attr1, attr2, ..."),
experimental!(register_attr),
@ -337,10 +332,10 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
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
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 \
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
// guarantee they'll have already been checked.
ungated!(
rustc_deprecated, AssumedUsed,
rustc_deprecated, Normal,
template!(List: r#"since = "version", reason = "...""#)
),
// FIXME(#14407)
ungated!(stable, AssumedUsed, template!(List: r#"feature = "name", since = "version""#)),
ungated!(stable, Normal, template!(List: r#"feature = "name", since = "version""#)),
// FIXME(#14407)
ungated!(
unstable, AssumedUsed,
unstable, Normal,
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
),
// FIXME(#14407)
ungated!(rustc_const_unstable, AssumedUsed, template!(List: r#"feature = "name""#)),
ungated!(rustc_const_unstable, Normal, template!(List: r#"feature = "name""#)),
// FIXME(#14407)
ungated!(rustc_const_stable, AssumedUsed, template!(List: r#"feature = "name""#)),
ungated!(rustc_const_stable, Normal, template!(List: r#"feature = "name""#)),
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",
),
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"
),
gated!(
@ -384,7 +379,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Internal attributes: Type system related:
// ==========================================================================
gated!(fundamental, AssumedUsed, template!(Word), experimental!(fundamental)),
gated!(fundamental, Normal, template!(Word), experimental!(fundamental)),
gated!(
may_dangle, Normal, template!(Word), dropck_eyepatch,
"`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:
// ==========================================================================
rustc_attr!(rustc_allocator, AssumedUsed, template!(Word), IMPL_DETAIL),
rustc_attr!(rustc_allocator_nounwind, AssumedUsed, template!(Word), IMPL_DETAIL),
rustc_attr!(rustc_allocator, Normal, 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!(
default_lib_allocator, AssumedUsed, template!(Word), allocator_internals,
default_lib_allocator, Normal, template!(Word), allocator_internals,
experimental!(default_lib_allocator),
),
gated!(
needs_allocator, Normal, template!(Word), allocator_internals,
experimental!(needs_allocator),
),
gated!(panic_runtime, AssumedUsed, template!(Word), experimental!(panic_runtime)),
gated!(needs_panic_runtime, AssumedUsed, template!(Word), experimental!(needs_panic_runtime)),
gated!(panic_runtime, Normal, template!(Word), experimental!(panic_runtime)),
gated!(needs_panic_runtime, Normal, template!(Word), experimental!(needs_panic_runtime)),
gated!(
compiler_builtins, AssumedUsed, template!(Word),
compiler_builtins, Normal, template!(Word),
"the `#[compiler_builtins]` attribute is used to identify the `compiler_builtins` crate \
which contains compiler-rt intrinsics and will never be stable",
),
gated!(
profiler_runtime, AssumedUsed, template!(Word),
profiler_runtime, Normal, template!(Word),
"the `#[profiler_runtime]` attribute is used to identify the `profiler_builtins` crate \
which contains the profiler runtime and will never be stable",
),
@ -423,23 +418,23 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ==========================================================================
gated!(
linkage, AssumedUsed, template!(NameValueStr: "external|internal|..."),
linkage, Normal, template!(NameValueStr: "external|internal|..."),
"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:
// ==========================================================================
rustc_attr!(
rustc_builtin_macro, AssumedUsed,
rustc_builtin_macro, Normal,
template!(Word, List: "name, /*opt*/ attributes(name1, name2, ...)"),
IMPL_DETAIL,
),
rustc_attr!(rustc_proc_macro_decls, Normal, template!(Word), INTERNAL_UNSTABLE),
rustc_attr!(
rustc_macro_transparency, AssumedUsed,
rustc_macro_transparency, Normal,
template!(NameValueStr: "transparent|semitransparent|opaque"),
"used internally for testing macro hygiene",
),
@ -449,7 +444,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// ==========================================================================
rustc_attr!(
rustc_on_unimplemented, AssumedUsed,
rustc_on_unimplemented, Normal,
template!(
List: r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
NameValueStr: "message"
@ -457,31 +452,31 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
INTERNAL_UNSTABLE
),
// 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:
// ==========================================================================
rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL),
rustc_attr!(rustc_legacy_const_generics, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE),
rustc_attr!(rustc_promotable, Normal, template!(Word), IMPL_DETAIL),
rustc_attr!(rustc_legacy_const_generics, Normal, template!(List: "N"), INTERNAL_UNSTABLE),
// ==========================================================================
// Internal attributes, Layout related:
// ==========================================================================
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 \
niche optimizations in libcore and will never be stable",
),
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 \
niche optimizations in libcore and will never be stable",
),
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 \
niche optimizations in libcore and will never be stable",
),
@ -506,7 +501,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
),
gated!(
// Used in resolve:
prelude_import, AssumedUsed, template!(Word),
prelude_import, Normal, template!(Word),
"`#[prelude_import]` is for use by rustc only",
),
gated!(
@ -514,7 +509,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
"unboxed_closures are still evolving",
),
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 \
overflow checking behavior of several libcore functions that are inlined \
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_regions, Normal, template!(Word)),
rustc_attr!(
TEST, rustc_error, AssumedUsed,
TEST, rustc_error, Normal,
template!(Word, List: "delay_span_bug_from_inside_query")
),
rustc_attr!(TEST, rustc_dump_user_substs, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_evaluate_where_clauses, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")),
rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")),
rustc_attr!(TEST, rustc_dump_user_substs, Normal, template!(Word)),
rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word)),
rustc_attr!(TEST, rustc_if_this_changed, Normal, template!(Word, List: "DepNode")),
rustc_attr!(TEST, rustc_then_this_would_need, Normal, template!(List: "DepNode")),
rustc_attr!(
TEST, rustc_clean, AssumedUsed,
TEST, rustc_clean, Normal,
template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#),
),
rustc_attr!(
TEST, rustc_partition_reused, AssumedUsed,
TEST, rustc_partition_reused, Normal,
template!(List: r#"cfg = "...", module = "...""#),
),
rustc_attr!(
TEST, rustc_partition_codegened, AssumedUsed,
TEST, rustc_partition_codegened, Normal,
template!(List: r#"cfg = "...", module = "...""#),
),
rustc_attr!(
TEST, rustc_expected_cgu_reuse, AssumedUsed,
TEST, rustc_expected_cgu_reuse, Normal,
template!(List: r#"cfg = "...", module = "...", kind = "...""#),
),
rustc_attr!(TEST, rustc_synthetic, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_symbol_name, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_polymorphize_error, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_def_path, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_mir, AssumedUsed, template!(List: "arg1, arg2, ...")),
rustc_attr!(TEST, rustc_dump_program_clauses, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_dump_env_program_clauses, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_object_lifetime_default, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_dump_vtable, AssumedUsed, template!(Word)),
rustc_attr!(TEST, rustc_synthetic, Normal, template!(Word)),
rustc_attr!(TEST, rustc_symbol_name, Normal, template!(Word)),
rustc_attr!(TEST, rustc_polymorphize_error, Normal, template!(Word)),
rustc_attr!(TEST, rustc_def_path, Normal, template!(Word)),
rustc_attr!(TEST, rustc_mir, Normal, template!(List: "arg1, arg2, ...")),
rustc_attr!(TEST, rustc_dump_program_clauses, Normal, template!(Word)),
rustc_attr!(TEST, rustc_dump_env_program_clauses, Normal, template!(Word)),
rustc_attr!(TEST, rustc_object_lifetime_default, Normal, template!(Word)),
rustc_attr!(TEST, rustc_dump_vtable, Normal, template!(Word)),
rustc_attr!(TEST, rustc_dummy, Normal, template!(Word /* doesn't matter*/)),
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",
),
];

View File

@ -123,7 +123,7 @@ impl IfThisChanged<'tcx> {
let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id());
let attrs = self.tcx.hir().attrs(hir_id);
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 = match dep_node_interned {
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));
} 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 = match dep_node_interned {
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> {
fn check_attr(&self, attr: &ast::Attribute) {
let (expected_reuse, comp_kind) =
if self.tcx.sess.check_name(attr, sym::rustc_partition_reused) {
(CguReuse::PreLto, ComparisonKind::AtLeast)
} else if self.tcx.sess.check_name(attr, sym::rustc_partition_codegened) {
(CguReuse::No, ComparisonKind::Exact)
} else if self.tcx.sess.check_name(attr, sym::rustc_expected_cgu_reuse) {
match self.field(attr, sym::kind) {
sym::no => (CguReuse::No, ComparisonKind::Exact),
sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
other => {
self.tcx.sess.span_fatal(
attr.span,
&format!("unknown cgu-reuse-kind `{}` specified", other),
);
}
let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) {
(CguReuse::PreLto, ComparisonKind::AtLeast)
} else if attr.has_name(sym::rustc_partition_codegened) {
(CguReuse::No, ComparisonKind::Exact)
} else if attr.has_name(sym::rustc_expected_cgu_reuse) {
match self.field(attr, sym::kind) {
sym::no => (CguReuse::No, ComparisonKind::Exact),
sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
other => {
self.tcx.sess.span_fatal(
attr.span,
&format!("unknown cgu-reuse-kind `{}` specified", other),
);
}
} else {
return;
};
}
} else {
return;
};
if !self.tcx.sess.opts.debugging_opts.query_dep_graph {
self.tcx.sess.span_fatal(

View File

@ -159,7 +159,7 @@ pub struct DirtyCleanVisitor<'tcx> {
impl DirtyCleanVisitor<'tcx> {
/// Possibly "deserialize" the attribute into a clean/dirty 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
return None;
}
@ -427,7 +427,7 @@ pub struct FindAllAttrs<'tcx> {
impl FindAllAttrs<'tcx> {
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;
}

View File

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

View File

@ -46,7 +46,6 @@ use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt};
use rustc_session::lint::FutureIncompatibilityReason;
use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@ -344,7 +343,7 @@ impl UnsafeCode {
impl EarlyLintPass for UnsafeCode {
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| {
lint.build(
"`allow_internal_unsafe` allows defining \
@ -492,12 +491,12 @@ pub struct MissingDoc {
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() {
return true;
}
if !sess.check_name(attr, sym::doc) {
if !attr.has_name(sym::doc) {
return false;
}
@ -554,7 +553,7 @@ impl MissingDoc {
}
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 {
cx.struct_span_lint(
MISSING_DOCS,
@ -568,10 +567,10 @@ impl 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()
|| attrs.iter().any(|attr| {
cx.sess().check_name(attr, sym::doc)
attr.has_name(sym::doc)
&& match attr.meta_item_list() {
None => false,
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 has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a));
let has_doc = attrs.iter().any(has_doc);
if !has_doc {
cx.struct_span_lint(
MISSING_DOCS,
@ -999,7 +998,7 @@ impl EarlyLintPass for DeprecatedAttr {
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 msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
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);
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| {
let mut err = lint.build("unused doc comment");
err.span_label(
@ -1301,7 +1300,7 @@ declare_lint_pass!(
impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
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() {
for item in items {
cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
@ -2771,7 +2770,7 @@ impl ClashingExternDeclarations {
overridden_link_name,
tcx.get_attrs(fi.def_id.to_def_id())
.iter()
.find(|at| tcx.sess.check_name(at, sym::link_name))
.find(|at| at.has_name(sym::link_name))
.unwrap()
.span,
)

View File

@ -236,8 +236,6 @@ impl<'s> LintLevelsBuilder<'s> {
Some(lvl) => lvl,
};
self.sess.mark_attr_used(attr);
let mut metas = unwrap_or!(attr.meta_item_list(), continue);
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
// May Depend on constants elsewhere
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.
UnstableFeatures: UnstableFeatures,
// 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 {
tcx.get_attrs(def.did)
.iter()
.any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed))
tcx.get_attrs(def.did).iter().any(|a| a.has_name(sym::rustc_nonnull_optimization_guaranteed))
}
/// `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::{ExprKind, StmtKind};
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, Applicability};
use rustc_feature::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_middle::ty::adjustment;
use rustc_middle::ty::{self, Ty};
use rustc_session::lint::builtin::UNUSED_ATTRIBUTES;
use rustc_span::symbol::Symbol;
use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, DUMMY_SP};
use tracing::debug;
declare_lint! {
/// The `unused_must_use` lint detects unused result of a type flagged as
/// `#[must_use]`.
@ -308,7 +303,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
descr_post_path: &str,
) -> bool {
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| {
let msg = format!(
"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)]
enum UnusedDelimsCtx {
FunctionArg,

View File

@ -3042,6 +3042,7 @@ declare_lint_pass! {
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
UNSUPPORTED_CALLING_CONVENTIONS,
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
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() {
Some(item) => item,
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 {
for attr in krate_attrs {
if !sess.check_name(attr, name) {
if !attr.has_name(name) {
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>) {
let attrs = self.get_attrs(def_id);
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,
None => return Bound::Unbounded,
};

View File

@ -338,7 +338,7 @@ impl RustcMirAttrs {
let rustc_mir_attrs = attrs
.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()));
for attr in rustc_mir_attrs {

View File

@ -30,12 +30,12 @@ pub struct MoveDataParamEnv<'tcx> {
}
pub(crate) fn has_rustc_mir_with(
sess: &Session,
_sess: &Session,
attrs: &[ast::Attribute],
name: Symbol,
) -> Option<MetaItem> {
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();
for item in items.iter().flat_map(|l| l.iter()) {
match item.meta_item() {

View File

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

View File

@ -13,9 +13,10 @@ use rustc_ast::tokenstream::{AttrAnnotatedTokenStream, AttrAnnotatedTokenTree};
use rustc_ast::tokenstream::{Spacing, TokenStream};
use rustc_ast::AstLike;
use rustc_ast::Attribute;
use rustc_ast::{AttrItem, MetaItem};
use rustc_ast_pretty::pprust;
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_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);
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_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_parse = { path = "../rustc_parse" }
rustc_session = { path = "../rustc_session" }
rustc_target = { path = "../rustc_target" }
rustc_ast = { path = "../rustc_ast" }
@ -18,3 +19,4 @@ rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
rustc_lexer = { path = "../rustc_lexer" }
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::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_feature::{AttributeType, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
@ -66,9 +68,10 @@ impl CheckAttrVisitor<'tcx> {
) {
let mut is_valid = true;
let mut specified_inline = None;
let mut seen = FxHashSet::default();
let attrs = self.tcx.hir().attrs(hir_id);
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::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
sym::marker => self.check_marker(hir_id, attr, span, target),
@ -101,14 +104,72 @@ impl CheckAttrVisitor<'tcx> {
sym::default_method_body_is_const => {
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,
};
is_valid &= attr_is_valid;
// lint-only checks
match attr.name_or_empty() {
sym::cold => self.check_cold(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::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])
}
sym::automatically_derived => {
self.check_generic_attr(hir_id, attr, target, &[Target::Impl])
}
sym::no_implicit_prelude => {
self.check_generic_attr(hir_id, attr, target, &[Target::Mod])
}
_ => {}
}
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 +272,37 @@ 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
});
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.
fn check_naked(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) -> bool {
match target {
@ -1555,6 +1647,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> {
@ -1675,7 +1833,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
for attr in attrs {
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
.struct_span_err(
attr.span,
@ -1692,7 +1850,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
fn check_invalid_macro_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
for attr in attrs {
if tcx.sess.check_name(attr, sym::inline) {
if attr.has_name(sym::inline) {
struct_span_err!(
tcx.sess,
attr.span,

View File

@ -15,7 +15,6 @@ use rustc_hir as hir;
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE};
use rustc_span::symbol::{sym, Symbol};
@ -51,7 +50,7 @@ impl<'tcx> DiagnosticItemCollector<'tcx> {
fn observe_item(&mut self, def_id: LocalDefId) {
let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_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
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.
fn extract(sess: &Session, attrs: &[ast::Attribute]) -> Option<Symbol> {
/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.p
fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
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::ty::TyCtxt;
use rustc_ast::Attribute;
use rustc_errors::{pluralize, struct_span_err};
use rustc_hir as hir;
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) {
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) {
match ITEM_REFS.get(&value).cloned() {
// Known lang item with attribute on correct target.

View File

@ -27,7 +27,7 @@ impl ItemLikeVisitor<'tcx> for LayoutTest<'tcx> {
| ItemKind::Struct(..)
| ItemKind::Union(..) => {
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);
}
}

View File

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

View File

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

View File

@ -148,7 +148,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> {
}
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
.sess
.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 {
let name = attr.name_or_empty();
if unstable_attrs.contains(&name) {
self.tcx.sess.mark_attr_used(attr);
struct_span_err!(
self.tcx.sess,
attr.span,

View File

@ -1,5 +1,6 @@
//! Validity checking for weak lang items
use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
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<'_>) {
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());
if let Some((lang_item, _)) = lang_items::extract(check_name, attrs) {
self.register(lang_item, i.span);

View File

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

View File

@ -885,9 +885,7 @@ impl Visitor<'tcx> for EmbargoVisitor<'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.
let attrs = self.tcx.hir().attrs(md.hir_id());
if attr::find_transparency(&self.tcx.sess, &attrs, md.ast.macro_rules).0
!= Transparency::Opaque
{
if attr::find_transparency(&attrs, md.ast.macro_rules).0 != Transparency::Opaque {
// `#[macro_export]`-ed `macro_rules!` are `Public` since they
// ignore their containing path to always appear at the crate root.
if md.ast.macro_rules {

View File

@ -195,7 +195,7 @@ impl<'a> Resolver<'a> {
crate fn get_macro(&mut self, res: Res) -> Option<Lrc<SyntaxExtension>> {
match res {
Res::Def(DefKind::Macro(..), def_id) => Some(self.get_macro_by_def_id(def_id)),
Res::NonMacroAttr(attr_kind) => Some(self.non_macro_attr(attr_kind.is_used())),
Res::NonMacroAttr(_) => Some(self.non_macro_attr.clone()),
_ => None,
}
}
@ -1059,7 +1059,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
let mut import_all = None;
let mut single_imports = Vec::new();
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() {
struct_span_err!(
self.r.session,
@ -1165,7 +1165,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
/// Returns `true` if this attribute list contains `macro_use`.
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
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 mut err = self.r.session.struct_span_warn(attr.span, msg);
if let ast::AttrStyle::Inner = attr.style {
@ -1173,7 +1173,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
} else {
err.emit();
}
} else if !self.r.session.check_name(attr, sym::macro_use) {
} else if !attr.has_name(sym::macro_use) {
continue;
}

View File

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

View File

@ -968,7 +968,7 @@ pub struct Resolver<'a> {
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
dummy_ext_bang: Lrc<SyntaxExtension>,
dummy_ext_derive: Lrc<SyntaxExtension>,
non_macro_attrs: [Lrc<SyntaxExtension>; 2],
non_macro_attr: Lrc<SyntaxExtension>,
local_macro_def_scopes: FxHashMap<LocalDefId, Module<'a>>,
ast_transform_scopes: FxHashMap<LocalExpnId, Module<'a>>,
unused_macros: FxHashMap<LocalDefId, (NodeId, Span)>,
@ -1293,8 +1293,6 @@ impl<'a> Resolver<'a> {
macros::registered_attrs_and_tools(session, &krate.attrs);
let features = session.features_untracked();
let non_macro_attr =
|mark_used| Lrc::new(SyntaxExtension::non_macro_attr(mark_used, session.edition()));
let mut resolver = Resolver {
session,
@ -1361,7 +1359,7 @@ impl<'a> Resolver<'a> {
macro_map: FxHashMap::default(),
dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())),
dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())),
non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
non_macro_attr: Lrc::new(SyntaxExtension::non_macro_attr(session.edition())),
invocation_parent_scopes: Default::default(),
output_macro_rules_scopes: Default::default(),
helper_attrs: Default::default(),
@ -1476,15 +1474,11 @@ impl<'a> Resolver<'a> {
self.crate_loader.cstore()
}
fn non_macro_attr(&self, mark_used: bool) -> Lrc<SyntaxExtension> {
self.non_macro_attrs[mark_used as usize].clone()
}
fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc<SyntaxExtension> {
match macro_kind {
MacroKind::Bang => self.dummy_ext_bang.clone(),
MacroKind::Derive => self.dummy_ext_derive.clone(),
MacroKind::Attr => self.non_macro_attr(true),
MacroKind::Attr => self.non_macro_attr.clone(),
}
}
@ -3381,9 +3375,8 @@ impl<'a> Resolver<'a> {
let parse_attrs = || {
let attrs = self.cstore().item_attrs(def_id, self.session);
let attr = attrs
.iter()
.find(|a| self.session.check_name(a, sym::rustc_legacy_const_generics))?;
let attr =
attrs.iter().find(|a| a.has_name(sym::rustc_legacy_const_generics))?;
let mut ret = vec![];
for meta in attr.meta_item_list()? {
match meta.literal()?.kind {

View File

@ -213,8 +213,6 @@ pub struct Session {
/// Set of enabled features for the current target.
pub target_features: FxHashSet<Symbol>,
used_attrs: Lock<MarkedAttrs>,
/// `Span`s for `if` conditions that we have suggested turning into `if let`.
pub if_let_suggestions: Lock<FxHashSet<Span>>,
}
@ -1066,39 +1064,14 @@ impl Session {
== 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 {
[sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
.iter()
.any(|kind| self.check_name(attr, *kind))
.any(|kind| attr.has_name(*kind))
}
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>(
@ -1106,7 +1079,7 @@ impl Session {
attrs: &'a [Attribute],
name: Symbol,
) -> 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>(
@ -1114,7 +1087,7 @@ impl Session {
attrs: &'a [Attribute],
name: Symbol,
) -> 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(
@ -1122,7 +1095,7 @@ impl Session {
attrs: &[Attribute],
name: 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()),
asm_arch,
target_features: FxHashSet::default(),
used_attrs: Lock::new(MarkedAttrs::new()),
if_let_suggestions: Default::default(),
};

View File

@ -35,7 +35,7 @@ impl SymbolNamesTest<'tcx> {
fn process_attrs(&mut self, def_id: LocalDefId) {
let tcx = self.tcx;
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 instance = Instance::new(
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-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()));
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
// `as_mut`?
.any(|a| self.sess().check_name(a, sym::rustc_conversion_suggestion))
.any(|a| a.has_name(sym::rustc_conversion_suggestion))
});
methods

View File

@ -21,6 +21,7 @@ use crate::constrained_generic_params as cgp;
use crate::errors;
use crate::middle::resolve_lifetime as rl;
use rustc_ast as ast;
use rustc_ast::Attribute;
use rustc_ast::{MetaItemKind, NestedMetaItem};
use rustc_attr::{list_contains_name, InlineAttr, InstructionSetAttr, OptimizeAttr};
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 no_sanitize_span = None;
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;
} else if tcx.sess.check_name(attr, sym::rustc_allocator) {
} else if attr.has_name(sym::rustc_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) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
} else {
@ -2786,9 +2787,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
)
.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 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]`
struct_span_err!(
tcx.sess,
@ -2810,7 +2811,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
)
.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) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
} else {
@ -2823,19 +2824,19 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
)
.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;
} else if tcx.sess.check_name(attr, sym::naked) {
} else if attr.has_name(sym::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;
} 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;
} 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;
} else if tcx.sess.check_name(attr, sym::used) {
} else if attr.has_name(sym::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 { .. }) {
struct_span_err!(
tcx.sess,
@ -2850,15 +2851,15 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
.emit();
}
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;
} 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 {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit();
}
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 s.as_str().contains('\0') {
// `#[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);
}
} 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.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
// The `#[target_feature]` attribute is allowed on
@ -2913,11 +2914,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
&supported_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() {
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 val.as_str().bytes().any(|b| b == 0) {
let msg = format!(
@ -2930,14 +2931,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
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();
} else if tcx.sess.check_name(attr, sym::link_ordinal) {
} else if attr.has_name(sym::link_ordinal) {
link_ordinal_span = Some(attr.span);
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
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);
if let Some(list) = attr.meta_item_list() {
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) {
Some(MetaItemKind::List(ref items)) => match items.as_slice() {
[NestedMetaItem::MetaItem(set)] => {
@ -3026,7 +3027,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
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() {
Some(items) => match items.as_slice() {
[item] => match item.name_value_literal() {
@ -3064,12 +3065,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
return ia;
}
match attr.meta().map(|i| i.kind) {
Some(MetaItemKind::Word) => {
tcx.sess.mark_attr_used(attr);
InlineAttr::Hint
}
Some(MetaItemKind::Word) => InlineAttr::Hint,
Some(MetaItemKind::List(ref items)) => {
tcx.sess.mark_attr_used(attr);
inline_span = Some(attr.span);
if items.len() != 1 {
struct_span_err!(
@ -3112,7 +3109,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs {
ia
}
Some(MetaItemKind::List(ref items)) => {
tcx.sess.mark_attr_used(attr);
inline_span = Some(attr.span);
if items.len() != 1 {
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) {
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) {
codegen_fn_attrs.export_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) {
if tcx.sess.check_name(attr, sym::track_caller) {
if attr.has_name(sym::track_caller) {
tcx.sess
.struct_span_err(
attr.span,
@ -405,7 +405,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) {
let attrs = tcx.hir().attrs(start_id);
for attr in attrs {
if tcx.sess.check_name(attr, sym::track_caller) {
if attr.has_name(sym::track_caller) {
tcx.sess
.struct_span_err(
attr.span,

View File

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

View File

@ -4,10 +4,10 @@
#![deny(unused)]
#[cfg_attr(FALSE,)] //~ ERROR unused attribute
#[cfg_attr(FALSE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes
fn _f() {}
#[cfg_attr(TRUE,)] //~ ERROR unused attribute
#[cfg_attr(TRUE,)] //~ ERROR `#[cfg_attr]` does not expand to any attributes
fn _g() {}
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
|
LL | #[cfg_attr(FALSE,)]
@ -11,7 +11,7 @@ LL | #![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
|
LL | #[cfg_attr(TRUE,)]

View File

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

View File

@ -49,14 +49,14 @@
#![macro_use] // (allowed if no argument; see issue-43160-gating-of-macro_use.rs)
// skipping testing of cfg
// skipping testing of cfg_attr
#![should_panic] //~ WARN unused attribute
#![ignore] //~ WARN unused attribute
#![should_panic] //~ WARN `#[should_panic]` only has an effect
#![ignore] //~ WARN `#[ignore]` only has an effect on functions
#![no_implicit_prelude]
#![reexport_test_harness_main = "2900"]
// see gated-link-args.rs
// 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")
#![proc_macro_derive()] //~ WARN unused attribute
#![proc_macro_derive()] //~ WARN `#[proc_macro_derive]` only has an effect
#![doc = "2400"]
#![cold] //~ WARN attribute should be applied to a function
//~^ WARN
@ -182,35 +182,35 @@ mod macro_use {
mod inner { #![macro_use] }
#[macro_use] fn f() { }
//~^ WARN unused attribute
//~^ `#[macro_use]` only has an effect
#[macro_use] struct S;
//~^ WARN unused attribute
//~^ `#[macro_use]` only has an effect
#[macro_use] type T = S;
//~^ WARN unused attribute
//~^ `#[macro_use]` only has an effect
#[macro_use] impl S { }
//~^ WARN unused attribute
//~^ `#[macro_use]` only has an effect
}
#[macro_export]
//~^ WARN unused attribute
//~^ WARN `#[macro_export]` only has an effect on macro definitions
mod macro_export {
mod inner { #![macro_export] }
//~^ WARN unused attribute
//~^ WARN `#[macro_export]` only has an effect on macro definitions
#[macro_export] fn f() { }
//~^ WARN unused attribute
//~^ WARN `#[macro_export]` only has an effect on macro definitions
#[macro_export] struct S;
//~^ WARN unused attribute
//~^ WARN `#[macro_export]` only has an effect on macro definitions
#[macro_export] type T = S;
//~^ WARN unused attribute
//~^ WARN `#[macro_export]` only has an effect on macro definitions
#[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
@ -263,35 +263,34 @@ mod path {
mod inner { #![path="3800"] }
#[path = "3800"] fn f() { }
//~^ WARN unused attribute
//~^ WARN `#[path]` only has an effect
#[path = "3800"] struct S;
//~^ WARN unused attribute
//~^ WARN `#[path]` only has an effect
#[path = "3800"] type T = S;
//~^ WARN unused attribute
//~^ WARN `#[path]` only has an effect
#[path = "3800"] impl S { }
//~^ WARN unused attribute
//~^ WARN `#[path]` only has an effect
}
#[automatically_derived]
//~^ WARN unused attribute
//~^ WARN `#[automatically_derived]` only has an effect
mod automatically_derived {
mod inner { #![automatically_derived] }
//~^ WARN unused attribute
//~^ WARN `#[automatically_derived]
#[automatically_derived] fn f() { }
//~^ WARN unused attribute
//~^ WARN `#[automatically_derived]
#[automatically_derived] struct S;
//~^ WARN unused attribute
//~^ WARN `#[automatically_derived]
#[automatically_derived] type T = S;
//~^ WARN unused attribute
//~^ WARN `#[automatically_derived]
#[automatically_derived] impl S { }
//~^ WARN unused attribute
}
#[no_mangle]
@ -335,79 +334,75 @@ mod no_mangle {
}
#[should_panic]
//~^ WARN unused attribute
//~^ WARN `#[should_panic]` only has an effect on
mod should_panic {
mod inner { #![should_panic] }
//~^ WARN unused attribute
//~^ WARN `#[should_panic]` only has an effect on
#[should_panic] fn f() { }
//~^ WARN unused attribute
#[should_panic] struct S;
//~^ WARN unused attribute
//~^ WARN `#[should_panic]` only has an effect on
#[should_panic] type T = S;
//~^ WARN unused attribute
//~^ WARN `#[should_panic]` only has an effect on
#[should_panic] impl S { }
//~^ WARN unused attribute
//~^ WARN `#[should_panic]` only has an effect on
}
#[ignore]
//~^ WARN unused attribute
//~^ WARN `#[ignore]` only has an effect on functions
mod ignore {
mod inner { #![ignore] }
//~^ WARN unused attribute
//~^ WARN `#[ignore]` only has an effect on functions
#[ignore] fn f() { }
//~^ WARN unused attribute
#[ignore] struct S;
//~^ WARN unused attribute
//~^ WARN `#[ignore]` only has an effect on functions
#[ignore] type T = S;
//~^ WARN unused attribute
//~^ WARN `#[ignore]` only has an effect on functions
#[ignore] impl S { }
//~^ WARN unused attribute
//~^ WARN `#[ignore]` only has an effect on functions
}
#[no_implicit_prelude]
//~^ WARN unused attribute
mod no_implicit_prelude {
mod inner { #![no_implicit_prelude] }
//~^ WARN unused attribute
#[no_implicit_prelude] fn f() { }
//~^ WARN unused attribute
//~^ WARN `#[no_implicit_prelude]` only has an effect
#[no_implicit_prelude] struct S;
//~^ WARN unused attribute
//~^ WARN `#[no_implicit_prelude]` only has an effect
#[no_implicit_prelude] type T = S;
//~^ WARN unused attribute
//~^ WARN `#[no_implicit_prelude]` only has an effect
#[no_implicit_prelude] impl S { }
//~^ WARN unused attribute
//~^ WARN `#[no_implicit_prelude]` only has an effect
}
#[reexport_test_harness_main = "2900"]
//~^ WARN unused attribute
//~^ WARN crate-level attribute should be
mod reexport_test_harness_main {
mod inner { #![reexport_test_harness_main="2900"] }
//~^ WARN unused attribute
//~^ WARN crate-level attribute should be
#[reexport_test_harness_main = "2900"] fn f() { }
//~^ WARN unused attribute
//~^ WARN crate-level attribute should be
#[reexport_test_harness_main = "2900"] struct S;
//~^ WARN unused attribute
//~^ WARN crate-level attribute should be
#[reexport_test_harness_main = "2900"] type T = S;
//~^ WARN unused attribute
//~^ WARN crate-level attribute should be
#[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.
@ -419,41 +414,35 @@ mod macro_escape {
//~| HELP try an outer attribute: `#[macro_use]`
#[macro_escape] fn f() { }
//~^ WARN unused attribute
//~^ WARN `#[macro_escape]` only has an effect
#[macro_escape] struct S;
//~^ WARN unused attribute
//~^ WARN `#[macro_escape]` only has an effect
#[macro_escape] type T = S;
//~^ WARN unused attribute
//~^ WARN `#[macro_escape]` only has an effect
#[macro_escape] impl S { }
//~^ WARN unused attribute
//~^ WARN `#[macro_escape]` only has an effect
}
#[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 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() { }
//~^ 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;
//~^ 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;
//~^ 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 { }
//~^ 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
@ -633,104 +622,80 @@ mod windows_subsystem {
// BROKEN USES OF CRATE-LEVEL BUILT-IN ATTRIBUTES
#[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 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() { }
//~^ 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;
//~^ 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;
//~^ 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 { }
//~^ WARN unused attribute
//~| WARN crate-level attribute should be an inner attribute
//~^ WARN crate-level attribute should be an inner attribute
}
#[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 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() { }
//~^ 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;
//~^ 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;
//~^ 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 { }
//~^ WARN unused attribute
//~| WARN crate-level attribute should be an inner attribute
//~^ WARN crate-level attribute should be an inner attribute
}
#[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 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() { }
//~^ 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;
//~^ 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;
//~^ 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 { }
//~^ WARN unused attribute
//~| WARN crate-level attribute should be an inner attribute
//~^ WARN crate-level attribute should be an inner attribute
}
#[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 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() { }
//~^ 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;
//~^ 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;
//~^ 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 { }
//~^ WARN unused attribute
//~| WARN crate-level attribute should be an inner attribute
//~^ WARN crate-level attribute should be an inner attribute
}
#[no_builtins]
@ -747,53 +712,41 @@ mod no_builtins {
}
#[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 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() { }
//~^ 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;
//~^ 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;
//~^ 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 { }
//~^ 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"]
//~^ 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 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() { }
//~^ 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;
//~^ 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;
//~^ 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 { }
//~^ WARN unused attribute
//~| WARN crate-level attribute should be an inner attribute
//~^ WARN crate-level attribute should be an inner attribute
}
fn main() {}

View File

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

View File

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

View File

@ -4,9 +4,7 @@
#![deny(unused_attributes)]
mod a {
#![crate_type = "bin"] //~ ERROR unused attribute
//~^ ERROR should be in the root module
#![crate_type = "bin"] //~ ERROR should be in the root module
}
#[crate_type = "bin"] fn main() {} //~ ERROR unused attribute
//~^ ERROR should be an inner
#[crate_type = "bin"] fn main() {} //~ 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
|
LL | #![crate_type = "bin"]
@ -10,23 +10,11 @@ note: the lint level is defined here
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]`
--> $DIR/lint-misplaced-attr.rs:11:1
--> $DIR/lint-misplaced-attr.rs:10:1
|
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.
#[macro_export]
#[macro_use] //~ ERROR unused attribute
#[path="foo"] //~ ERROR unused attribute
#[recursion_limit="1"] //~ ERROR unused attribute
//~| ERROR crate-level attribute should be an inner attribute
#[macro_use] //~ ERROR `#[macro_use]` only has an effect
#[path="foo"] //~ ERROR #[path]` only has an effect
#[recursion_limit="1"] //~ ERROR crate-level attribute should be an inner attribute
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
|
LL | #[macro_use]
@ -10,23 +10,17 @@ note: the lint level is defined here
LL | #![deny(unused_attributes)]
| ^^^^^^^^^^^^^^^^^
error: unused attribute
error: `#[path]` only has an effect on modules
--> $DIR/unused-attr-macro-rules.rs:8:1
|
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]`
--> $DIR/unused-attr-macro-rules.rs:9: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