1
Fork 0

Enforce crate level attributes checks

This commit is contained in:
Guillaume Gomez 2020-10-03 20:45:39 +02:00
parent 6ec2474622
commit 3641a37455
10 changed files with 377 additions and 372 deletions

View file

@ -19,8 +19,8 @@ use rustc_hir::{
use rustc_hir::{MethodKind, Target};
use rustc_session::lint::builtin::{CONFLICTING_REPR_HINTS, UNUSED_ATTRIBUTES};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
pub(crate) fn target_from_impl_item<'tcx>(
tcx: TyCtxt<'tcx>,
@ -821,6 +821,33 @@ fn is_c_like_enum(item: &Item<'_>) -> bool {
}
}
fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) {
const ATTRS_TO_CHECK: &[Symbol] = &[
sym::macro_export,
sym::repr,
sym::path,
sym::automatically_derived,
sym::start,
sym::main,
];
for attr in attrs {
for attr_to_check in ATTRS_TO_CHECK {
if tcx.sess.check_name(attr, *attr_to_check) {
tcx.sess
.struct_span_err(
attr.span,
&format!(
"`{}` attribute cannot be used at crate level",
attr_to_check.to_ident_string()
),
)
.emit();
}
}
}
}
fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
tcx.hir()
.visit_item_likes_in_module(module_def_id, &mut CheckAttrVisitor { tcx }.as_deep_visitor());
@ -828,10 +855,11 @@ fn check_mod_attrs(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
CheckAttrVisitor { tcx }.check_attributes(
CRATE_HIR_ID,
tcx.hir().krate_attrs(),
&tcx.hir().span(CRATE_HIR_ID),
&DUMMY_SP,
Target::Mod,
None,
);
check_invalid_crate_level_attr(tcx, tcx.hir().krate_attrs());
}
}

View file

@ -78,29 +78,38 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType)
// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
// (with `ast::Item`), so make sure to keep them in sync.
fn entry_point_type(sess: &Session, item: &Item<'_>, at_root: bool) -> EntryPointType {
match item.kind {
ItemKind::Fn(..) => {
if sess.contains_name(&item.attrs, sym::start) {
EntryPointType::Start
} else if sess.contains_name(&item.attrs, sym::main) {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
if at_root {
// This is a top-level function so can be `main`.
EntryPointType::MainNamed
} else {
EntryPointType::OtherMain
}
} else {
EntryPointType::None
}
if sess.contains_name(&item.attrs, sym::start) {
EntryPointType::Start
} else if sess.contains_name(&item.attrs, sym::main) {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
if at_root {
// This is a top-level function so can be `main`.
EntryPointType::MainNamed
} else {
EntryPointType::OtherMain
}
_ => EntryPointType::None,
} else {
EntryPointType::None
}
}
fn throw_attr_err(sess: &Session, span: Span, attr: &str) {
sess.struct_span_err(span, &format!("`{}` attribute can only be used on functions", attr))
.emit();
}
fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
match entry_point_type(&ctxt.session, item, at_root) {
EntryPointType::None => (),
_ if !matches!(item.kind, ItemKind::Fn(..)) => {
if let Some(attr) = ctxt.session.find_by_name(item.attrs, sym::start) {
throw_attr_err(&ctxt.session, attr.span, "start");
}
if let Some(attr) = ctxt.session.find_by_name(item.attrs, sym::main) {
throw_attr_err(&ctxt.session, attr.span, "main");
}
}
EntryPointType::MainNamed => {
if ctxt.main_fn.is_none() {
ctxt.main_fn = Some((item.hir_id, item.span));
@ -137,7 +146,6 @@ fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
.emit();
}
}
EntryPointType::None => (),
}
}