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:
parent
b6e334d873
commit
af46699f81
62 changed files with 535 additions and 739 deletions
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -753,11 +753,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
|
|||
}
|
||||
}
|
||||
}
|
||||
SyntaxExtensionKind::NonMacroAttr { mark_used } => {
|
||||
SyntaxExtensionKind::NonMacroAttr { mark_used: _ } => {
|
||||
self.cx.expanded_inert_attrs.mark(&attr);
|
||||
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))
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue