Remove Session.used_attrs and move logic to CheckAttrVisitor

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

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

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

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

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

View file

@ -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,