Skip to content

Commit fcf850f

Browse files
committed
Auto merge of #59655 - Zoxc:symbols, r=petrochenkov
Use a proc macro to declare preallocated symbols r? @petrochenkov
2 parents 1edb01b + f598091 commit fcf850f

File tree

13 files changed

+327
-141
lines changed

13 files changed

+327
-141
lines changed

Cargo.lock

+1
Original file line numberDiff line numberDiff line change
@@ -3387,6 +3387,7 @@ dependencies = [
33873387
"arena 0.0.0",
33883388
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
33893389
"rustc_data_structures 0.0.0",
3390+
"rustc_macros 0.1.0",
33903391
"scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
33913392
"serialize 0.0.0",
33923393
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",

src/librustc/middle/lib_features.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::ty::TyCtxt;
88
use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
99
use syntax::symbol::Symbol;
1010
use syntax::ast::{Attribute, MetaItem, MetaItemKind};
11-
use syntax_pos::Span;
11+
use syntax_pos::{Span, symbols};
1212
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
1313
use rustc_macros::HashStable;
1414
use errors::DiagnosticId;
@@ -51,12 +51,12 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> {
5151
}
5252

5353
fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option<Symbol>, Span)> {
54-
let stab_attrs = vec!["stable", "unstable", "rustc_const_unstable"];
54+
let stab_attrs = [symbols::stable, symbols::unstable, symbols::rustc_const_unstable];
5555

5656
// Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`,
5757
// `#[rustc_const_unstable (..)]`).
5858
if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| {
59-
attr.check_name(stab_attr)
59+
attr.check_name(**stab_attr)
6060
}) {
6161
let meta_item = attr.meta();
6262
if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta_item {

src/librustc_incremental/persist/dirty_clean.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -599,7 +599,7 @@ impl<'a, 'tcx> FindAllAttrs<'a, 'tcx> {
599599

600600
fn is_active_attr(&mut self, attr: &Attribute) -> bool {
601601
for attr_name in &self.attr_names {
602-
if attr.check_name(attr_name) && check_config(self.tcx, attr) {
602+
if attr.check_name(*attr_name) && check_config(self.tcx, attr) {
603603
return true;
604604
}
605605
}

src/librustc_lint/unused.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {
228228

229229
let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
230230
for &(ref name, ty) in plugin_attributes.iter() {
231-
if ty == AttributeType::Whitelisted && attr.check_name(&name) {
231+
if ty == AttributeType::Whitelisted && attr.check_name(&**name) {
232232
debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty);
233233
break;
234234
}

src/librustc_macros/src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,16 @@ use proc_macro::TokenStream;
99

1010
mod hash_stable;
1111
mod query;
12+
mod symbols;
1213

1314
#[proc_macro]
1415
pub fn rustc_queries(input: TokenStream) -> TokenStream {
1516
query::rustc_queries(input)
1617
}
1718

19+
#[proc_macro]
20+
pub fn symbols(input: TokenStream) -> TokenStream {
21+
symbols::symbols(input)
22+
}
23+
1824
decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive);

src/librustc_macros/src/symbols.rs

+163
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
use proc_macro::TokenStream;
2+
use syn::{
3+
Token, Ident, LitStr,
4+
braced, parse_macro_input,
5+
};
6+
use syn::parse::{Result, Parse, ParseStream};
7+
use syn;
8+
use std::collections::HashSet;
9+
use quote::quote;
10+
11+
#[allow(non_camel_case_types)]
12+
mod kw {
13+
syn::custom_keyword!(Keywords);
14+
syn::custom_keyword!(Other);
15+
}
16+
17+
struct Keyword {
18+
name: Ident,
19+
value: LitStr,
20+
}
21+
22+
impl Parse for Keyword {
23+
fn parse(input: ParseStream<'_>) -> Result<Self> {
24+
let name = input.parse()?;
25+
input.parse::<Token![:]>()?;
26+
let value = input.parse()?;
27+
input.parse::<Token![,]>()?;
28+
29+
Ok(Keyword {
30+
name,
31+
value,
32+
})
33+
}
34+
}
35+
36+
struct Symbol(Ident);
37+
38+
impl Parse for Symbol {
39+
fn parse(input: ParseStream<'_>) -> Result<Self> {
40+
let ident: Ident = input.parse()?;
41+
input.parse::<Token![,]>()?;
42+
43+
Ok(Symbol(ident))
44+
}
45+
}
46+
47+
/// A type used to greedily parse another type until the input is empty.
48+
struct List<T>(Vec<T>);
49+
50+
impl<T: Parse> Parse for List<T> {
51+
fn parse(input: ParseStream<'_>) -> Result<Self> {
52+
let mut list = Vec::new();
53+
while !input.is_empty() {
54+
list.push(input.parse()?);
55+
}
56+
Ok(List(list))
57+
}
58+
}
59+
60+
struct Input {
61+
keywords: List<Keyword>,
62+
symbols: List<Symbol>,
63+
}
64+
65+
impl Parse for Input {
66+
fn parse(input: ParseStream<'_>) -> Result<Self> {
67+
input.parse::<kw::Keywords>()?;
68+
let content;
69+
braced!(content in input);
70+
let keywords = content.parse()?;
71+
72+
input.parse::<kw::Other>()?;
73+
let content;
74+
braced!(content in input);
75+
let symbols = content.parse()?;
76+
77+
Ok(Input {
78+
keywords,
79+
symbols,
80+
})
81+
}
82+
}
83+
84+
pub fn symbols(input: TokenStream) -> TokenStream {
85+
let input = parse_macro_input!(input as Input);
86+
87+
let mut keyword_stream = quote! {};
88+
let mut symbols_stream = quote! {};
89+
let mut prefill_stream = quote! {};
90+
let mut from_str_stream = quote! {};
91+
let mut counter = 0u32;
92+
let mut keys = HashSet::<String>::new();
93+
94+
let mut check_dup = |str: &str| {
95+
if !keys.insert(str.to_string()) {
96+
panic!("Symbol `{}` is duplicated", str);
97+
}
98+
};
99+
100+
for keyword in &input.keywords.0 {
101+
let name = &keyword.name;
102+
let value = &keyword.value;
103+
check_dup(&value.value());
104+
prefill_stream.extend(quote! {
105+
#value,
106+
});
107+
keyword_stream.extend(quote! {
108+
pub const #name: Keyword = Keyword {
109+
ident: Ident::with_empty_ctxt(super::Symbol::new(#counter))
110+
};
111+
});
112+
from_str_stream.extend(quote! {
113+
#value => Ok(#name),
114+
});
115+
counter += 1;
116+
}
117+
118+
for symbol in &input.symbols.0 {
119+
let value = &symbol.0;
120+
let value_str = value.to_string();
121+
check_dup(&value_str);
122+
prefill_stream.extend(quote! {
123+
#value_str,
124+
});
125+
symbols_stream.extend(quote! {
126+
pub const #value: Symbol = Symbol::new(#counter);
127+
});
128+
counter += 1;
129+
}
130+
131+
TokenStream::from(quote! {
132+
macro_rules! keywords {
133+
() => {
134+
#keyword_stream
135+
136+
impl std::str::FromStr for Keyword {
137+
type Err = ();
138+
139+
fn from_str(s: &str) -> Result<Self, ()> {
140+
match s {
141+
#from_str_stream
142+
_ => Err(()),
143+
}
144+
}
145+
}
146+
}
147+
}
148+
149+
macro_rules! symbols {
150+
() => {
151+
#symbols_stream
152+
}
153+
}
154+
155+
impl Interner {
156+
pub fn fresh() -> Self {
157+
Interner::prefill(&[
158+
#prefill_stream
159+
])
160+
}
161+
}
162+
})
163+
}

src/libsyntax/ast.rs

+12
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,18 @@ pub struct Path {
6868
pub segments: Vec<PathSegment>,
6969
}
7070

71+
impl PartialEq<Symbol> for Path {
72+
fn eq(&self, symbol: &Symbol) -> bool {
73+
self.segments.len() == 1 && {
74+
let name = self.segments[0].ident.name;
75+
// Make sure these symbols are pure strings
76+
debug_assert!(!symbol.is_gensymed());
77+
debug_assert!(!name.is_gensymed());
78+
name == *symbol
79+
}
80+
}
81+
}
82+
7183
impl<'a> PartialEq<&'a str> for Path {
7284
fn eq(&self, string: &&'a str) -> bool {
7385
self.segments.len() == 1 && self.segments[0].ident.name == *string

src/libsyntax/attr/mod.rs

+12-3
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ impl NestedMetaItem {
8181
}
8282

8383
/// Returns `true` if this list item is a MetaItem with a name of `name`.
84-
pub fn check_name(&self, name: &str) -> bool {
84+
pub fn check_name<T>(&self, name: T) -> bool
85+
where
86+
Path: PartialEq<T>,
87+
{
8588
self.meta_item().map_or(false, |meta_item| meta_item.check_name(name))
8689
}
8790

@@ -151,7 +154,10 @@ impl Attribute {
151154
/// attribute is marked as used.
152155
///
153156
/// To check the attribute name without marking it used, use the `path` field directly.
154-
pub fn check_name(&self, name: &str) -> bool {
157+
pub fn check_name<T>(&self, name: T) -> bool
158+
where
159+
Path: PartialEq<T>,
160+
{
155161
let matches = self.path == name;
156162
if matches {
157163
mark_used(self);
@@ -244,7 +250,10 @@ impl MetaItem {
244250
}
245251
}
246252

247-
pub fn check_name(&self, name: &str) -> bool {
253+
pub fn check_name<T>(&self, name: T) -> bool
254+
where
255+
Path: PartialEq<T>,
256+
{
248257
self.path == name
249258
}
250259

src/libsyntax/feature_gate.rs

+14-14
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::tokenstream::TokenTree;
2828
use errors::{DiagnosticBuilder, Handler};
2929
use rustc_data_structures::fx::FxHashMap;
3030
use rustc_target::spec::abi::Abi;
31-
use syntax_pos::{Span, DUMMY_SP};
31+
use syntax_pos::{Span, DUMMY_SP, symbols};
3232
use log::debug;
3333

3434
use std::env;
@@ -1366,7 +1366,7 @@ impl<'a> Context<'a> {
13661366
}
13671367
} else if n == "doc" {
13681368
if let Some(content) = attr.meta_item_list() {
1369-
if content.iter().any(|c| c.check_name("include")) {
1369+
if content.iter().any(|c| c.check_name(symbols::include)) {
13701370
gate_feature!(self, external_doc, attr.span,
13711371
"#[doc(include = \"...\")] is experimental"
13721372
);
@@ -1667,33 +1667,33 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
16671667
// check for gated attributes
16681668
self.context.check_attribute(attr, false);
16691669

1670-
if attr.check_name("doc") {
1670+
if attr.check_name(symbols::doc) {
16711671
if let Some(content) = attr.meta_item_list() {
1672-
if content.len() == 1 && content[0].check_name("cfg") {
1672+
if content.len() == 1 && content[0].check_name(symbols::cfg) {
16731673
gate_feature_post!(&self, doc_cfg, attr.span,
16741674
"#[doc(cfg(...))] is experimental"
16751675
);
1676-
} else if content.iter().any(|c| c.check_name("masked")) {
1676+
} else if content.iter().any(|c| c.check_name(symbols::masked)) {
16771677
gate_feature_post!(&self, doc_masked, attr.span,
16781678
"#[doc(masked)] is experimental"
16791679
);
1680-
} else if content.iter().any(|c| c.check_name("spotlight")) {
1680+
} else if content.iter().any(|c| c.check_name(symbols::spotlight)) {
16811681
gate_feature_post!(&self, doc_spotlight, attr.span,
16821682
"#[doc(spotlight)] is experimental"
16831683
);
1684-
} else if content.iter().any(|c| c.check_name("alias")) {
1684+
} else if content.iter().any(|c| c.check_name(symbols::alias)) {
16851685
gate_feature_post!(&self, doc_alias, attr.span,
16861686
"#[doc(alias = \"...\")] is experimental"
16871687
);
1688-
} else if content.iter().any(|c| c.check_name("keyword")) {
1688+
} else if content.iter().any(|c| c.check_name(symbols::keyword)) {
16891689
gate_feature_post!(&self, doc_keyword, attr.span,
16901690
"#[doc(keyword = \"...\")] is experimental"
16911691
);
16921692
}
16931693
}
16941694
}
16951695

1696-
match BUILTIN_ATTRIBUTES.iter().find(|(name, ..)| attr.path == name) {
1696+
match BUILTIN_ATTRIBUTES.iter().find(|(name, ..)| attr.path == *name) {
16971697
Some(&(name, _, template, _)) => self.check_builtin_attribute(attr, name, template),
16981698
None => if let Some(TokenTree::Token(_, token::Eq)) = attr.tokens.trees().next() {
16991699
// All key-value attributes are restricted to meta-item syntax.
@@ -1748,7 +1748,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
17481748
ast::ItemKind::Struct(..) => {
17491749
for attr in attr::filter_by_name(&i.attrs[..], "repr") {
17501750
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1751-
if item.check_name("simd") {
1751+
if item.check_name(symbols::simd) {
17521752
gate_feature_post!(&self, repr_simd, attr.span,
17531753
"SIMD types are experimental and possibly buggy");
17541754
}
@@ -1759,7 +1759,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
17591759
ast::ItemKind::Enum(..) => {
17601760
for attr in attr::filter_by_name(&i.attrs[..], "repr") {
17611761
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
1762-
if item.check_name("align") {
1762+
if item.check_name(symbols::align) {
17631763
gate_feature_post!(&self, repr_align_enum, attr.span,
17641764
"`#[repr(align(x))]` on enums is experimental");
17651765
}
@@ -2083,7 +2083,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
20832083
// Process the edition umbrella feature-gates first, to ensure
20842084
// `edition_enabled_features` is completed before it's queried.
20852085
for attr in krate_attrs {
2086-
if !attr.check_name("feature") {
2086+
if !attr.check_name(symbols::feature) {
20872087
continue
20882088
}
20892089

@@ -2128,7 +2128,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
21282128
}
21292129

21302130
for attr in krate_attrs {
2131-
if !attr.check_name("feature") {
2131+
if !attr.check_name(symbols::feature) {
21322132
continue
21332133
}
21342134

@@ -2258,7 +2258,7 @@ fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
22582258
};
22592259
if !allow_features {
22602260
for attr in &krate.attrs {
2261-
if attr.check_name("feature") {
2261+
if attr.check_name(symbols::feature) {
22622262
let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
22632263
span_err!(span_handler, attr.span, E0554,
22642264
"#![feature] may not be used on the {} release channel",

src/libsyntax_ext/proc_macro_decls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ pub fn modify(sess: &ParseSess,
8787
}
8888

8989
pub fn is_proc_macro_attr(attr: &ast::Attribute) -> bool {
90-
PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(kind))
90+
PROC_MACRO_KINDS.iter().any(|kind| attr.check_name(*kind))
9191
}
9292

9393
impl<'a> CollectProcMacros<'a> {

0 commit comments

Comments
 (0)