1
Fork 0

Preallocate BUILTIN_ATTRIBUTES symbols and use a hash map instead of looping

This commit is contained in:
John Kåre Alsaker 2019-04-10 19:47:55 +02:00
parent fcf850f34a
commit b82ab24bbf
9 changed files with 645 additions and 417 deletions

View file

@ -3356,9 +3356,11 @@ name = "syntax"
version = "0.0.0"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_data_structures 0.0.0",
"rustc_errors 0.0.0",
"rustc_macros 0.1.0",
"rustc_target 0.0.0",
"scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serialize 0.0.0",

View file

@ -42,7 +42,7 @@ use syntax::edition::Edition;
use syntax::feature_gate::{AttributeGate, AttributeTemplate, AttributeType};
use syntax::feature_gate::{Stability, deprecated_attributes};
use syntax_pos::{BytePos, Span, SyntaxContext};
use syntax::symbol::keywords;
use syntax::symbol::{Symbol, keywords};
use syntax::errors::{Applicability, DiagnosticBuilder};
use syntax::print::pprust::expr_to_string;
use syntax::visit::FnKind;
@ -653,7 +653,7 @@ impl EarlyLintPass for AnonymousParameters {
pub struct DeprecatedAttr {
// This is not free to compute, so we want to keep it around, rather than
// compute it for every attribute.
depr_attrs: Vec<&'static (&'static str, AttributeType, AttributeTemplate, AttributeGate)>,
depr_attrs: Vec<&'static (Symbol, AttributeType, AttributeTemplate, AttributeGate)>,
}
impl_lint_pass!(DeprecatedAttr => []);
@ -668,9 +668,8 @@ impl DeprecatedAttr {
impl EarlyLintPass for DeprecatedAttr {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
let name = attr.name_or_empty();
for &&(n, _, _, ref g) in &self.depr_attrs {
if name == n {
if attr.ident().map(|ident| ident.name) == Some(n) {
if let &AttributeGate::Gated(Stability::Deprecated(link, suggestion),
ref name,
ref reason,

View file

@ -118,7 +118,7 @@ macro_rules! late_lint_passes {
UnusedBrokenConst: UnusedBrokenConst,
// Uses attr::is_used which is untracked, can't be an incremental module pass.
UnusedAttributes: UnusedAttributes,
UnusedAttributes: UnusedAttributes::new(),
// Needs to run after UnusedAttributes as it marks all `feature` attributes as used.
UnstableFeatures: UnstableFeatures,

View file

@ -3,15 +3,17 @@ use rustc::hir::def_id::DefId;
use rustc::lint;
use rustc::ty;
use rustc::ty::adjustment;
use rustc_data_structures::fx::FxHashMap;
use lint::{LateContext, EarlyContext, LintContext, LintArray};
use lint::{LintPass, EarlyLintPass, LateLintPass};
use syntax::ast;
use syntax::attr;
use syntax::errors::Applicability;
use syntax::feature_gate::{BUILTIN_ATTRIBUTES, AttributeType};
use syntax::feature_gate::{AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use syntax::print::pprust;
use syntax::symbol::keywords;
use syntax::symbol::Symbol;
use syntax::util::parser;
use syntax_pos::Span;
@ -210,17 +212,32 @@ declare_lint! {
"detects attributes that were not used by the compiler"
}
declare_lint_pass!(UnusedAttributes => [UNUSED_ATTRIBUTES]);
#[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<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
fn check_attribute(&mut self, cx: &LateContext<'_, '_>, attr: &ast::Attribute) {
debug!("checking attribute: {:?}", attr);
// Note that check_name() marks the attribute as used if it matches.
for &(name, ty, ..) in BUILTIN_ATTRIBUTES {
let attr_info = attr.ident().and_then(|ident| self.builtin_attributes.get(&ident.name));
if let Some(&&(name, ty, ..)) = attr_info {
match ty {
AttributeType::Whitelisted if attr.check_name(name) => {
AttributeType::Whitelisted => {
debug!("{:?} is Whitelisted", name);
break;
return;
}
_ => (),
}
@ -239,11 +256,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
debug!("Emitting warning for: {:?}", attr);
cx.span_lint(UNUSED_ATTRIBUTES, attr.span, "unused attribute");
// Is it a builtin attribute that must be used at the crate level?
let known_crate = BUILTIN_ATTRIBUTES.iter()
.find(|&&(builtin, ty, ..)| {
name == builtin && ty == AttributeType::CrateLevel
})
.is_some();
let known_crate = attr_info.map(|&&(_, ty, ..)| {
ty == AttributeType::CrateLevel
}).unwrap_or(false);
// Has a plugin registered this attribute as one that must be used at
// the crate level?

View file

@ -360,8 +360,8 @@ impl<'a> Resolver<'a> {
let attr_candidates = BUILTIN_ATTRIBUTES
.iter()
.filter_map(|(name, _, _, gate)| {
if name.starts_with("rustc_") && !features.rustc_attrs {
.filter_map(|&(name, _, _, ref gate)| {
if name.as_str().starts_with("rustc_") && !features.rustc_attrs {
return None;
}
@ -376,7 +376,6 @@ impl<'a> Resolver<'a> {
_ => None,
}
})
.map(|name| Symbol::intern(name))
.chain(
// Add built-in macro attributes as well.
self.builtin_macros.iter().filter_map(|(name, binding)| {

View file

@ -14,8 +14,10 @@ bitflags = "1.0"
serialize = { path = "../libserialize" }
log = "0.4"
scoped-tls = "1.0"
lazy_static = "1.0.0"
syntax_pos = { path = "../libsyntax_pos" }
errors = { path = "../librustc_errors", package = "rustc_errors" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_macros = { path = "../librustc_macros" }
rustc_target = { path = "../librustc_target" }
smallvec = { version = "0.6.7", features = ["union", "may_dangle"] }

View file

@ -30,6 +30,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_target::spec::abi::Abi;
use syntax_pos::{Span, DUMMY_SP, symbols};
use log::debug;
use lazy_static::lazy_static;
use std::env;
@ -811,102 +812,126 @@ macro_rules! cfg_fn {
}}
}
pub fn deprecated_attributes() -> Vec<&'static (&'static str, AttributeType,
pub fn deprecated_attributes() -> Vec<&'static (Symbol, AttributeType,
AttributeTemplate, AttributeGate)> {
BUILTIN_ATTRIBUTES.iter().filter(|(.., gate)| gate.is_deprecated()).collect()
}
pub fn is_builtin_attr_name(name: ast::Name) -> bool {
BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, ..)| name == builtin_name)
BUILTIN_ATTRIBUTE_MAP.get(&name).is_some()
}
pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
BUILTIN_ATTRIBUTES.iter().any(|&(builtin_name, ..)| attr.path == builtin_name)
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name)).is_some()
}
// Attributes that have a special meaning to rustc or rustdoc
pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, AttributeGate)] = &[
/// Attributes that have a special meaning to rustc or rustdoc
pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// Normal attributes
("warn", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated),
("allow", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated),
("forbid", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated),
("deny", Normal, template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#), Ungated),
(
symbols::warn,
Normal,
template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
Ungated
),
(
symbols::allow,
Normal,
template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
Ungated
),
(
symbols::forbid,
Normal,
template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
Ungated
),
(
symbols::deny,
Normal,
template!(List: r#"lint1, lint2, ..., /*opt*/ reason = "...""#),
Ungated
),
("macro_use", Normal, template!(Word, List: "name1, name2, ..."), Ungated),
("macro_export", Normal, template!(Word, List: "local_inner_macros"), Ungated),
("plugin_registrar", Normal, template!(Word), Ungated),
(symbols::macro_use, Normal, template!(Word, List: "name1, name2, ..."), Ungated),
(symbols::macro_export, Normal, template!(Word, List: "local_inner_macros"), Ungated),
(symbols::plugin_registrar, Normal, template!(Word), Ungated),
("cfg", Normal, template!(List: "predicate"), Ungated),
("cfg_attr", Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated),
("main", Normal, template!(Word), Ungated),
("start", Normal, template!(Word), Ungated),
("repr", Normal, template!(List: "C, packed, ..."), Ungated),
("path", Normal, template!(NameValueStr: "file"), Ungated),
("automatically_derived", Normal, template!(Word), Ungated),
("no_mangle", Normal, template!(Word), Ungated),
("no_link", Normal, template!(Word), Ungated),
("derive", Normal, template!(List: "Trait1, Trait2, ..."), Ungated),
("should_panic", Normal, template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
Ungated),
("ignore", Normal, template!(Word, NameValueStr: "reason"), Ungated),
("no_implicit_prelude", Normal, template!(Word), Ungated),
("reexport_test_harness_main", Normal, template!(NameValueStr: "name"), Ungated),
("link_args", Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable,
(symbols::cfg, Normal, template!(List: "predicate"), Ungated),
(symbols::cfg_attr, Normal, template!(List: "predicate, attr1, attr2, ..."), Ungated),
(symbols::main, Normal, template!(Word), Ungated),
(symbols::start, Normal, template!(Word), Ungated),
(symbols::repr, Normal, template!(List: "C, packed, ..."), Ungated),
(symbols::path, Normal, template!(NameValueStr: "file"), Ungated),
(symbols::automatically_derived, Normal, template!(Word), Ungated),
(symbols::no_mangle, Normal, template!(Word), Ungated),
(symbols::no_link, Normal, template!(Word), Ungated),
(symbols::derive, Normal, template!(List: "Trait1, Trait2, ..."), Ungated),
(
symbols::should_panic,
Normal,
template!(Word, List: r#"expected = "reason"#, NameValueStr: "reason"),
Ungated
),
(symbols::ignore, Normal, template!(Word, NameValueStr: "reason"), Ungated),
(symbols::no_implicit_prelude, Normal, template!(Word), Ungated),
(symbols::reexport_test_harness_main, Normal, template!(NameValueStr: "name"), Ungated),
(symbols::link_args, Normal, template!(NameValueStr: "args"), Gated(Stability::Unstable,
"link_args",
"the `link_args` attribute is experimental and not \
portable across platforms, it is recommended to \
use `#[link(name = \"foo\")] instead",
cfg_fn!(link_args))),
("macro_escape", Normal, template!(Word), Ungated),
(symbols::macro_escape, Normal, template!(Word), Ungated),
// RFC #1445.
("structural_match", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::structural_match, Whitelisted, template!(Word), Gated(Stability::Unstable,
"structural_match",
"the semantics of constant patterns is \
not yet settled",
cfg_fn!(structural_match))),
// RFC #2008
("non_exhaustive", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::non_exhaustive, Whitelisted, template!(Word), Gated(Stability::Unstable,
"non_exhaustive",
"non exhaustive is an experimental feature",
cfg_fn!(non_exhaustive))),
// RFC #1268
("marker", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::marker, Normal, template!(Word), Gated(Stability::Unstable,
"marker_trait_attr",
"marker traits is an experimental feature",
cfg_fn!(marker_trait_attr))),
("plugin", CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable,
(symbols::plugin, CrateLevel, template!(List: "name|name(args)"), Gated(Stability::Unstable,
"plugin",
"compiler plugins are experimental \
and possibly buggy",
cfg_fn!(plugin))),
("no_std", CrateLevel, template!(Word), Ungated),
("no_core", CrateLevel, template!(Word), Gated(Stability::Unstable,
(symbols::no_std, CrateLevel, template!(Word), Ungated),
(symbols::no_core, CrateLevel, template!(Word), Gated(Stability::Unstable,
"no_core",
"no_core is experimental",
cfg_fn!(no_core))),
("lang", Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable,
(symbols::lang, Normal, template!(NameValueStr: "name"), Gated(Stability::Unstable,
"lang_items",
"language items are subject to change",
cfg_fn!(lang_items))),
("linkage", Whitelisted, template!(NameValueStr: "external|internal|..."),
(symbols::linkage, Whitelisted, template!(NameValueStr: "external|internal|..."),
Gated(Stability::Unstable,
"linkage",
"the `linkage` attribute is experimental \
and not portable across platforms",
cfg_fn!(linkage))),
("thread_local", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::thread_local, Whitelisted, template!(Word), Gated(Stability::Unstable,
"thread_local",
"`#[thread_local]` is an experimental feature, and does \
not currently handle destructors",
cfg_fn!(thread_local))),
("rustc_on_unimplemented", Whitelisted, template!(List:
(symbols::rustc_on_unimplemented, Whitelisted, template!(List:
r#"/*opt*/ message = "...", /*opt*/ label = "...", /*opt*/ note = "...""#,
NameValueStr: "message"),
Gated(Stability::Unstable,
@ -914,101 +939,101 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
"the `#[rustc_on_unimplemented]` attribute \
is an experimental feature",
cfg_fn!(on_unimplemented))),
("rustc_const_unstable", Normal, template!(List: r#"feature = "name""#),
(symbols::rustc_const_unstable, Normal, template!(List: r#"feature = "name""#),
Gated(Stability::Unstable,
"rustc_const_unstable",
"the `#[rustc_const_unstable]` attribute \
is an internal feature",
cfg_fn!(rustc_const_unstable))),
("global_allocator", Normal, template!(Word), Ungated),
("default_lib_allocator", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::global_allocator, Normal, template!(Word), Ungated),
(symbols::default_lib_allocator, Whitelisted, template!(Word), Gated(Stability::Unstable,
"allocator_internals",
"the `#[default_lib_allocator]` \
attribute is an experimental feature",
cfg_fn!(allocator_internals))),
("needs_allocator", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::needs_allocator, Normal, template!(Word), Gated(Stability::Unstable,
"allocator_internals",
"the `#[needs_allocator]` \
attribute is an experimental \
feature",
cfg_fn!(allocator_internals))),
("panic_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
"panic_runtime",
"the `#[panic_runtime]` attribute is \
an experimental feature",
cfg_fn!(panic_runtime))),
("needs_panic_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::needs_panic_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
"needs_panic_runtime",
"the `#[needs_panic_runtime]` \
attribute is an experimental \
feature",
cfg_fn!(needs_panic_runtime))),
("rustc_outlives", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_outlives, Normal, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_outlives]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_variance", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_variance, Normal, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_variance]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_layout", Normal, template!(List: "field1, field2, ..."),
(symbols::rustc_layout, Normal, template!(List: "field1, field2, ..."),
Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_layout]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_layout_scalar_valid_range_start", Whitelisted, template!(List: "value"),
(symbols::rustc_layout_scalar_valid_range_start, Whitelisted, template!(List: "value"),
Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_layout_scalar_valid_range_start]` attribute \
is just used to enable niche optimizations in libcore \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_layout_scalar_valid_range_end", Whitelisted, template!(List: "value"),
(symbols::rustc_layout_scalar_valid_range_end, Whitelisted, template!(List: "value"),
Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_layout_scalar_valid_range_end]` attribute \
is just used to enable niche optimizations in libcore \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_regions", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_regions, Normal, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_regions]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_error", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_error, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_error]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_dump_user_substs", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_dump_user_substs, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"this attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_if_this_changed", Whitelisted, template!(Word, List: "DepNode"),
(symbols::rustc_if_this_changed, Whitelisted, template!(Word, List: "DepNode"),
Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_if_this_changed]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_then_this_would_need", Whitelisted, template!(List: "DepNode"),
(symbols::rustc_then_this_would_need, Whitelisted, template!(List: "DepNode"),
Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_if_this_changed]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_dirty", Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
(symbols::rustc_dirty, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
/*opt*/ except = "...""#),
Gated(Stability::Unstable,
"rustc_attrs",
@ -1016,7 +1041,7 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_clean", Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
(symbols::rustc_clean, Whitelisted, template!(List: r#"cfg = "...", /*opt*/ label = "...",
/*opt*/ except = "...""#),
Gated(Stability::Unstable,
"rustc_attrs",
@ -1024,21 +1049,33 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_partition_reused", Whitelisted, template!(List: r#"cfg = "...", module = "...""#),
Gated(Stability::Unstable,
(
symbols::rustc_partition_reused,
Whitelisted,
template!(List: r#"cfg = "...", module = "...""#),
Gated(
Stability::Unstable,
"rustc_attrs",
"this attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_partition_codegened", Whitelisted, template!(List: r#"cfg = "...", module = "...""#),
Gated(Stability::Unstable,
cfg_fn!(rustc_attrs)
)
),
(
symbols::rustc_partition_codegened,
Whitelisted,
template!(List: r#"cfg = "...", module = "...""#),
Gated(
Stability::Unstable,
"rustc_attrs",
"this attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_expected_cgu_reuse", Whitelisted, template!(List: r#"cfg = "...", module = "...",
cfg_fn!(rustc_attrs),
)
),
(symbols::rustc_expected_cgu_reuse, Whitelisted, template!(List: r#"cfg = "...", module = "...",
kind = "...""#),
Gated(Stability::Unstable,
"rustc_attrs",
@ -1046,64 +1083,71 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_synthetic", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_synthetic, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"this attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_symbol_name", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_symbol_name, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"internal rustc attributes will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_def_path", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_def_path, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"internal rustc attributes will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_mir", Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable,
(symbols::rustc_mir, Whitelisted, template!(List: "arg1, arg2, ..."), Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_mir]` attribute \
is just used for rustc unit tests \
and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_inherit_overflow_checks", Whitelisted, template!(Word), Gated(Stability::Unstable,
(
symbols::rustc_inherit_overflow_checks,
Whitelisted,
template!(Word),
Gated(
Stability::Unstable,
"rustc_attrs",
"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",
cfg_fn!(rustc_attrs))),
cfg_fn!(rustc_attrs),
)
),
("rustc_dump_program_clauses", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_dump_program_clauses, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_dump_program_clauses]` \
attribute is just used for rustc unit \
tests and will never be stable",
cfg_fn!(rustc_attrs))),
("rustc_test_marker", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_test_marker, Normal, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"the `#[rustc_test_marker]` attribute \
is used internally to track tests",
cfg_fn!(rustc_attrs))),
("rustc_transparent_macro", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_transparent_macro, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"used internally for testing macro hygiene",
cfg_fn!(rustc_attrs))),
("compiler_builtins", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::compiler_builtins, Whitelisted, template!(Word), Gated(Stability::Unstable,
"compiler_builtins",
"the `#[compiler_builtins]` attribute is used to \
identify the `compiler_builtins` crate which \
contains compiler-rt intrinsics and will never be \
stable",
cfg_fn!(compiler_builtins))),
("sanitizer_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::sanitizer_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
"sanitizer_runtime",
"the `#[sanitizer_runtime]` attribute is used to \
identify crates that contain the runtime of a \
sanitizer and will never be stable",
cfg_fn!(sanitizer_runtime))),
("profiler_runtime", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::profiler_runtime, Whitelisted, template!(Word), Gated(Stability::Unstable,
"profiler_runtime",
"the `#[profiler_runtime]` attribute is used to \
identify the `profiler_builtins` crate which \
@ -1111,70 +1155,81 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
stable",
cfg_fn!(profiler_runtime))),
("allow_internal_unstable", Normal, template!(Word, List: "feat1, feat2, ..."),
(symbols::allow_internal_unstable, Normal, template!(Word, List: "feat1, feat2, ..."),
Gated(Stability::Unstable,
"allow_internal_unstable",
EXPLAIN_ALLOW_INTERNAL_UNSTABLE,
cfg_fn!(allow_internal_unstable))),
("allow_internal_unsafe", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::allow_internal_unsafe, Normal, template!(Word), Gated(Stability::Unstable,
"allow_internal_unsafe",
EXPLAIN_ALLOW_INTERNAL_UNSAFE,
cfg_fn!(allow_internal_unsafe))),
("fundamental", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::fundamental, Whitelisted, template!(Word), Gated(Stability::Unstable,
"fundamental",
"the `#[fundamental]` attribute \
is an experimental feature",
cfg_fn!(fundamental))),
("proc_macro_derive", Normal, template!(List: "TraitName, \
(symbols::proc_macro_derive, Normal, template!(List: "TraitName, \
/*opt*/ attributes(name1, name2, ...)"),
Ungated),
("rustc_copy_clone_marker", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_copy_clone_marker, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"internal implementation detail",
cfg_fn!(rustc_attrs))),
// FIXME: #14408 whitelist docs since rustdoc looks at them
("doc", Whitelisted, template!(List: "hidden|inline|...", NameValueStr: "string"), Ungated),
(
symbols::doc,
Whitelisted,
template!(List: "hidden|inline|...", NameValueStr: "string"),
Ungated
),
// FIXME: #14406 these are processed in codegen, which happens after the
// lint pass
("cold", Whitelisted, template!(Word), Ungated),
("naked", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::cold, Whitelisted, template!(Word), Ungated),
(symbols::naked, Whitelisted, template!(Word), Gated(Stability::Unstable,
"naked_functions",
"the `#[naked]` attribute \
is an experimental feature",
cfg_fn!(naked_functions))),
("ffi_returns_twice", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::ffi_returns_twice, Whitelisted, template!(Word), Gated(Stability::Unstable,
"ffi_returns_twice",
"the `#[ffi_returns_twice]` attribute \
is an experimental feature",
cfg_fn!(ffi_returns_twice))),
("target_feature", Whitelisted, template!(List: r#"enable = "name""#), Ungated),
("export_name", Whitelisted, template!(NameValueStr: "name"), Ungated),
("inline", Whitelisted, template!(Word, List: "always|never"), Ungated),
("link", Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...",
(symbols::target_feature, Whitelisted, template!(List: r#"enable = "name""#), Ungated),
(symbols::export_name, Whitelisted, template!(NameValueStr: "name"), Ungated),
(symbols::inline, Whitelisted, template!(Word, List: "always|never"), Ungated),
(symbols::link, Whitelisted, template!(List: r#"name = "...", /*opt*/ kind = "dylib|static|...",
/*opt*/ cfg = "...""#), Ungated),
("link_name", Whitelisted, template!(NameValueStr: "name"), Ungated),
("link_section", Whitelisted, template!(NameValueStr: "name"), Ungated),
("no_builtins", Whitelisted, template!(Word), Ungated),
("no_mangle", Whitelisted, template!(Word), Ungated),
("no_debug", Whitelisted, template!(Word), Gated(
(symbols::link_name, Whitelisted, template!(NameValueStr: "name"), Ungated),
(symbols::link_section, Whitelisted, template!(NameValueStr: "name"), Ungated),
(symbols::no_builtins, Whitelisted, template!(Word), Ungated),
(symbols::no_debug, Whitelisted, template!(Word), Gated(
Stability::Deprecated("https://github.com/rust-lang/rust/issues/29721", None),
"no_debug",
"the `#[no_debug]` attribute was an experimental feature that has been \
deprecated due to lack of demand",
cfg_fn!(no_debug))),
("omit_gdb_pretty_printer_section", Whitelisted, template!(Word), Gated(Stability::Unstable,
(
symbols::omit_gdb_pretty_printer_section,
Whitelisted,
template!(Word),
Gated(
Stability::Unstable,
"omit_gdb_pretty_printer_section",
"the `#[omit_gdb_pretty_printer_section]` \
attribute is just used for the Rust test \
suite",
cfg_fn!(omit_gdb_pretty_printer_section))),
("unsafe_destructor_blind_to_params",
cfg_fn!(omit_gdb_pretty_printer_section)
)
),
(symbols::unsafe_destructor_blind_to_params,
Normal,
template!(Word),
Gated(Stability::Deprecated("https://github.com/rust-lang/rust/issues/34761",
@ -1183,34 +1238,47 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
"unsafe_destructor_blind_to_params has been replaced by \
may_dangle and will be removed in the future",
cfg_fn!(dropck_parametricity))),
("may_dangle",
(symbols::may_dangle,
Normal,
template!(Word),
Gated(Stability::Unstable,
"dropck_eyepatch",
"may_dangle has unstable semantics and may be removed in the future",
cfg_fn!(dropck_eyepatch))),
("unwind", Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable,
(symbols::unwind, Whitelisted, template!(List: "allowed|aborts"), Gated(Stability::Unstable,
"unwind_attributes",
"#[unwind] is experimental",
cfg_fn!(unwind_attributes))),
("used", Whitelisted, template!(Word), Ungated),
(symbols::used, Whitelisted, template!(Word), Ungated),
// used in resolve
("prelude_import", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::prelude_import, Whitelisted, template!(Word), Gated(Stability::Unstable,
"prelude_import",
"`#[prelude_import]` is for use by rustc only",
cfg_fn!(prelude_import))),
// FIXME: #14407 these are only looked at on-demand so we can't
// guarantee they'll have already been checked
("rustc_deprecated", Whitelisted, template!(List: r#"since = "version", reason = "...""#),
Ungated),
("must_use", Whitelisted, template!(Word, NameValueStr: "reason"), Ungated),
("stable", Whitelisted, template!(List: r#"feature = "name", since = "version""#), Ungated),
("unstable", Whitelisted, template!(List: r#"feature = "name", reason = "...", issue = "N""#),
Ungated),
("deprecated",
(
symbols::rustc_deprecated,
Whitelisted,
template!(List: r#"since = "version", reason = "...""#),
Ungated
),
(symbols::must_use, Whitelisted, template!(Word, NameValueStr: "reason"), Ungated),
(
symbols::stable,
Whitelisted,
template!(List: r#"feature = "name", since = "version""#),
Ungated
),
(
symbols::unstable,
Whitelisted,
template!(List: r#"feature = "name", reason = "...", issue = "N""#),
Ungated
),
(symbols::deprecated,
Normal,
template!(
Word,
@ -1220,73 +1288,88 @@ pub const BUILTIN_ATTRIBUTES: &[(&str, AttributeType, AttributeTemplate, Attribu
Ungated
),
("rustc_paren_sugar", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_paren_sugar, Normal, template!(Word), Gated(Stability::Unstable,
"unboxed_closures",
"unboxed_closures are still evolving",
cfg_fn!(unboxed_closures))),
("windows_subsystem", Whitelisted, template!(NameValueStr: "windows|console"), Ungated),
(symbols::windows_subsystem, Whitelisted, template!(NameValueStr: "windows|console"), Ungated),
("proc_macro_attribute", Normal, template!(Word), Ungated),
("proc_macro", Normal, template!(Word), Ungated),
(symbols::proc_macro_attribute, Normal, template!(Word), Ungated),
(symbols::proc_macro, Normal, template!(Word), Ungated),
("rustc_proc_macro_decls", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_proc_macro_decls, Normal, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"used internally by rustc",
cfg_fn!(rustc_attrs))),
("allow_fail", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::allow_fail, Normal, template!(Word), Gated(Stability::Unstable,
"allow_fail",
"allow_fail attribute is currently unstable",
cfg_fn!(allow_fail))),
("rustc_std_internal_symbol", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_std_internal_symbol, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"this is an internal attribute that will \
never be stable",
cfg_fn!(rustc_attrs))),
// whitelists "identity-like" conversion methods to suggest on type mismatch
("rustc_conversion_suggestion", Whitelisted, template!(Word), Gated(Stability::Unstable,
(symbols::rustc_conversion_suggestion, Whitelisted, template!(Word), Gated(Stability::Unstable,
"rustc_attrs",
"this is an internal attribute that will \
never be stable",
cfg_fn!(rustc_attrs))),
("rustc_args_required_const", Whitelisted, template!(List: "N"), Gated(Stability::Unstable,
"rustc_attrs",
"never will be stable",
cfg_fn!(rustc_attrs))),
(
symbols::rustc_args_required_const,
Whitelisted,
template!(List: "N"),
Gated(Stability::Unstable, "rustc_attrs", "never will be stable", cfg_fn!(rustc_attrs))
),
// RFC 2070
("panic_handler", Normal, template!(Word), Ungated),
(symbols::panic_handler, Normal, template!(Word), Ungated),
("alloc_error_handler", Normal, template!(Word), Gated(Stability::Unstable,
(symbols::alloc_error_handler, Normal, template!(Word), Gated(Stability::Unstable,
"alloc_error_handler",
"#[alloc_error_handler] is an unstable feature",
cfg_fn!(alloc_error_handler))),
// RFC 2412
("optimize", Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable,
(symbols::optimize, Whitelisted, template!(List: "size|speed"), Gated(Stability::Unstable,
"optimize_attribute",
"#[optimize] attribute is an unstable feature",
cfg_fn!(optimize_attribute))),
// Crate level attributes
("crate_name", CrateLevel, template!(NameValueStr: "name"), Ungated),
("crate_type", CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated),
("crate_id", CrateLevel, template!(NameValueStr: "ignored"), Ungated),
("feature", CrateLevel, template!(List: "name1, name1, ..."), Ungated),
("no_start", CrateLevel, template!(Word), Ungated),
("no_main", CrateLevel, template!(Word), Ungated),
("no_builtins", CrateLevel, template!(Word), Ungated),
("recursion_limit", CrateLevel, template!(NameValueStr: "N"), Ungated),
("type_length_limit", CrateLevel, template!(NameValueStr: "N"), Ungated),
("test_runner", CrateLevel, template!(List: "path"), Gated(Stability::Unstable,
(symbols::crate_name, CrateLevel, template!(NameValueStr: "name"), Ungated),
(symbols::crate_type, CrateLevel, template!(NameValueStr: "bin|lib|..."), Ungated),
(symbols::crate_id, CrateLevel, template!(NameValueStr: "ignored"), Ungated),
(symbols::feature, CrateLevel, template!(List: "name1, name1, ..."), Ungated),
(symbols::no_start, CrateLevel, template!(Word), Ungated),
(symbols::no_main, CrateLevel, template!(Word), Ungated),
(symbols::recursion_limit, CrateLevel, template!(NameValueStr: "N"), Ungated),
(symbols::type_length_limit, CrateLevel, template!(NameValueStr: "N"), Ungated),
(symbols::test_runner, CrateLevel, template!(List: "path"), Gated(Stability::Unstable,
"custom_test_frameworks",
EXPLAIN_CUSTOM_TEST_FRAMEWORKS,
cfg_fn!(custom_test_frameworks))),
];
pub type BuiltinAttribute = (Symbol, AttributeType, AttributeTemplate, AttributeGate);
lazy_static! {
pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap<Symbol, &'static BuiltinAttribute> = {
let mut map = FxHashMap::default();
for attr in BUILTIN_ATTRIBUTES.iter() {
if map.insert(attr.0, attr).is_some() {
panic!("duplicate builtin attribute `{}`", attr.0);
}
}
map
};
}
// cfg(...)'s that are feature gated
const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
// (name in cfg, feature, function to check if the feature is enabled)
@ -1353,18 +1436,21 @@ macro_rules! gate_feature {
}
impl<'a> Context<'a> {
fn check_attribute(&self, attr: &ast::Attribute, is_macro: bool) {
fn check_attribute(
&self,
attr: &ast::Attribute,
attr_info: Option<&BuiltinAttribute>,
is_macro: bool
) {
debug!("check_attribute(attr = {:?})", attr);
let name = attr.name_or_empty();
for &(n, ty, _template, ref gateage) in BUILTIN_ATTRIBUTES {
if name == n {
if let Some(&(name, ty, _template, ref gateage)) = attr_info {
if let Gated(_, name, desc, ref has_feature) = *gateage {
if !attr.span.allows_unstable(name) {
gate_feature_fn!(
self, has_feature, attr.span, name, desc, GateStrength::Hard
);
}
} else if n == "doc" {
} else if name == symbols::doc {
if let Some(content) = attr.meta_item_list() {
if content.iter().any(|c| c.check_name(symbols::include)) {
gate_feature!(self, external_doc, attr.span,
@ -1376,7 +1462,6 @@ impl<'a> Context<'a> {
debug!("check_attribute: {:?} is builtin, {:?}, {:?}", attr.path, ty, gateage);
return;
}
}
for &(ref n, ref ty) in self.plugin_attributes {
if attr.path == &**n {
// Plugins can't gate attributes, so we don't check for it
@ -1387,7 +1472,7 @@ impl<'a> Context<'a> {
}
}
if !attr::is_known(attr) {
if name.starts_with("rustc_") {
if attr.name_or_empty().starts_with("rustc_") {
let msg = "unless otherwise specified, attributes with the prefix `rustc_` \
are reserved for internal compiler diagnostics";
gate_feature!(self, rustc_attrs, attr.span, msg);
@ -1405,7 +1490,11 @@ impl<'a> Context<'a> {
pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
let cx = Context { features: features, parse_sess: parse_sess, plugin_attributes: &[] };
cx.check_attribute(attr, true);
cx.check_attribute(
attr,
attr.ident().and_then(|ident| BUILTIN_ATTRIBUTE_MAP.get(&ident.name).map(|a| *a)),
true
);
}
fn find_lang_feature_issue(feature: &str) -> Option<u32> {
@ -1542,6 +1631,7 @@ pub const EXPLAIN_UNSIZED_TUPLE_COERCION: &str =
struct PostExpansionVisitor<'a> {
context: &'a Context<'a>,
builtin_attributes: &'static FxHashMap<Symbol, &'static BuiltinAttribute>,
}
macro_rules! gate_feature_post {
@ -1615,15 +1705,15 @@ impl<'a> PostExpansionVisitor<'a> {
}
}
fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: &str,
fn check_builtin_attribute(&mut self, attr: &ast::Attribute, name: Symbol,
template: AttributeTemplate) {
// Some special attributes like `cfg` must be checked
// before the generic check, so we skip them here.
let should_skip = |name| name == "cfg";
let should_skip = |name| name == symbols::cfg;
// Some of previously accepted forms were used in practice,
// report them as warnings for now.
let should_warn = |name| name == "doc" || name == "ignore" ||
name == "inline" || name == "link";
let should_warn = |name| name == symbols::doc || name == symbols::ignore ||
name == symbols::inline || name == symbols::link;
match attr.parse_meta(self.context.parse_sess) {
Ok(meta) => if !should_skip(name) && !template.compatible(&meta.node) {
@ -1664,8 +1754,12 @@ impl<'a> PostExpansionVisitor<'a> {
impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
fn visit_attribute(&mut self, attr: &ast::Attribute) {
let attr_info = attr.ident().and_then(|ident| {
self.builtin_attributes.get(&ident.name).map(|a| *a)
});
// check for gated attributes
self.context.check_attribute(attr, false);
self.context.check_attribute(attr, attr_info, false);
if attr.check_name(symbols::doc) {
if let Some(content) = attr.meta_item_list() {
@ -1693,8 +1787,12 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
}
}
match BUILTIN_ATTRIBUTES.iter().find(|(name, ..)| attr.path == *name) {
Some(&(name, _, template, _)) => self.check_builtin_attribute(attr, name, template),
match attr_info {
Some(&(name, _, template, _)) => self.check_builtin_attribute(
attr,
name,
template
),
None => if let Some(TokenTree::Token(_, token::Eq)) = attr.tokens.trees().next() {
// All key-value attributes are restricted to meta-item syntax.
attr.parse_meta(self.context.parse_sess).map_err(|mut err| err.emit()).ok();
@ -2210,8 +2308,10 @@ pub fn check_crate(krate: &ast::Crate,
parse_sess: sess,
plugin_attributes,
};
let visitor = &mut PostExpansionVisitor { context: &ctx };
let visitor = &mut PostExpansionVisitor {
context: &ctx,
builtin_attributes: &*BUILTIN_ATTRIBUTE_MAP,
};
visit::walk_crate(visitor, krate);
}

View file

@ -100,8 +100,127 @@ symbols! {
// Other symbols that can be referred to with syntax_pos::symbols::*
Other {
doc, cfg, masked, spotlight, alias, keyword, feature, include, simd, align, stable,
unstable, rustc_const_unstable,
alias,
align,
alloc_error_handler,
allow,
allow_fail,
allow_internal_unsafe,
allow_internal_unstable,
automatically_derived,
cfg,
cfg_attr,
cold,
compiler_builtins,
crate_id,
crate_name,
crate_type,
default_lib_allocator,
deny,
deprecated,
derive,
doc,
export_name,
feature,
ffi_returns_twice,
forbid,
fundamental,
global_allocator,
ignore,
include,
inline,
keyword,
lang,
link,
link_args,
link_name,
link_section,
linkage,
macro_escape,
macro_export,
macro_use,
main,
marker,
masked,
may_dangle,
must_use,
naked,
needs_allocator,
needs_panic_runtime,
no_builtins,
no_core,
no_debug,
no_implicit_prelude,
no_link,
no_main,
no_mangle,
no_start,
no_std,
non_exhaustive,
omit_gdb_pretty_printer_section,
optimize,
panic_handler,
panic_runtime,
path,
plugin,
plugin_registrar,
prelude_import,
proc_macro,
proc_macro_attribute,
proc_macro_derive,
profiler_runtime,
recursion_limit,
reexport_test_harness_main,
repr,
rustc_args_required_const,
rustc_clean,
rustc_const_unstable,
rustc_conversion_suggestion,
rustc_copy_clone_marker,
rustc_def_path,
rustc_deprecated,
rustc_dirty,
rustc_dump_program_clauses,
rustc_dump_user_substs,
rustc_error,
rustc_expected_cgu_reuse,
rustc_if_this_changed,
rustc_inherit_overflow_checks,
rustc_layout,
rustc_layout_scalar_valid_range_end,
rustc_layout_scalar_valid_range_start,
rustc_mir,
rustc_on_unimplemented,
rustc_outlives,
rustc_paren_sugar,
rustc_partition_codegened,
rustc_partition_reused,
rustc_proc_macro_decls,
rustc_regions,
rustc_std_internal_symbol,
rustc_symbol_name,
rustc_synthetic,
rustc_test_marker,
rustc_then_this_would_need,
rustc_transparent_macro,
rustc_variance,
sanitizer_runtime,
should_panic,
simd,
spotlight,
stable,
start,
structural_match,
target_feature,
test_runner,
thread_local,
type_length_limit,
unsafe_destructor_blind_to_params,
unstable,
unwind,
used,
warn,
windows_subsystem,
}
}
@ -237,14 +356,6 @@ newtype_index! {
pub struct SymbolIndex { .. }
}
// The interner is pointed to by a thread local value which is only set on the main thread
// with parallelization is disabled. So we don't allow `Symbol` to transfer between threads
// to avoid panics and other errors, even though it would be memory safe to do so.
#[cfg(not(parallel_compiler))]
impl !Send for Symbol { }
#[cfg(not(parallel_compiler))]
impl !Sync for Symbol { }
impl Symbol {
const fn new(n: u32) -> Self {
Symbol(SymbolIndex::from_u32_const(n))