Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a proc macro to declare preallocated symbols #59655

Merged
merged 5 commits into from
Apr 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3387,6 +3387,7 @@ dependencies = [
"arena 0.0.0",
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_data_structures 0.0.0",
"rustc_macros 0.1.0",
"scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serialize 0.0.0",
"unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/middle/lib_features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::ty::TyCtxt;
use crate::hir::intravisit::{self, NestedVisitorMap, Visitor};
use syntax::symbol::Symbol;
use syntax::ast::{Attribute, MetaItem, MetaItemKind};
use syntax_pos::Span;
use syntax_pos::{Span, symbols};
use rustc_data_structures::fx::{FxHashSet, FxHashMap};
use rustc_macros::HashStable;
use errors::DiagnosticId;
Expand Down Expand Up @@ -51,12 +51,12 @@ impl<'a, 'tcx> LibFeatureCollector<'a, 'tcx> {
}

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

// Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`,
// `#[rustc_const_unstable (..)]`).
if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| {
attr.check_name(stab_attr)
attr.check_name(**stab_attr)
}) {
let meta_item = attr.meta();
if let Some(MetaItem { node: MetaItemKind::List(ref metas), .. }) = meta_item {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_incremental/persist/dirty_clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,7 +599,7 @@ impl<'a, 'tcx> FindAllAttrs<'a, 'tcx> {

fn is_active_attr(&mut self, attr: &Attribute) -> bool {
for attr_name in &self.attr_names {
if attr.check_name(attr_name) && check_config(self.tcx, attr) {
if attr.check_name(*attr_name) && check_config(self.tcx, attr) {
return true;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_lint/unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedAttributes {

let plugin_attributes = cx.sess().plugin_attributes.borrow_mut();
for &(ref name, ty) in plugin_attributes.iter() {
if ty == AttributeType::Whitelisted && attr.check_name(&name) {
if ty == AttributeType::Whitelisted && attr.check_name(&**name) {
debug!("{:?} (plugin attr) is whitelisted with ty {:?}", name, ty);
break;
}
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,16 @@ use proc_macro::TokenStream;

mod hash_stable;
mod query;
mod symbols;

#[proc_macro]
pub fn rustc_queries(input: TokenStream) -> TokenStream {
query::rustc_queries(input)
}

#[proc_macro]
pub fn symbols(input: TokenStream) -> TokenStream {
symbols::symbols(input)
}

decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive);
163 changes: 163 additions & 0 deletions src/librustc_macros/src/symbols.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use proc_macro::TokenStream;
use syn::{
Token, Ident, LitStr,
braced, parse_macro_input,
};
use syn::parse::{Result, Parse, ParseStream};
use syn;
use std::collections::HashSet;
use quote::quote;

#[allow(non_camel_case_types)]
mod kw {
syn::custom_keyword!(Keywords);
syn::custom_keyword!(Other);
}

struct Keyword {
name: Ident,
value: LitStr,
}

impl Parse for Keyword {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let name = input.parse()?;
input.parse::<Token![:]>()?;
let value = input.parse()?;
input.parse::<Token![,]>()?;

Ok(Keyword {
name,
value,
})
}
}

struct Symbol(Ident);

impl Parse for Symbol {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let ident: Ident = input.parse()?;
input.parse::<Token![,]>()?;

Ok(Symbol(ident))
}
}

/// A type used to greedily parse another type until the input is empty.
struct List<T>(Vec<T>);

impl<T: Parse> Parse for List<T> {
fn parse(input: ParseStream<'_>) -> Result<Self> {
let mut list = Vec::new();
while !input.is_empty() {
list.push(input.parse()?);
}
Ok(List(list))
}
}

struct Input {
keywords: List<Keyword>,
symbols: List<Symbol>,
}

impl Parse for Input {
fn parse(input: ParseStream<'_>) -> Result<Self> {
input.parse::<kw::Keywords>()?;
let content;
braced!(content in input);
let keywords = content.parse()?;

input.parse::<kw::Other>()?;
let content;
braced!(content in input);
let symbols = content.parse()?;

Ok(Input {
keywords,
symbols,
})
}
}

pub fn symbols(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as Input);

let mut keyword_stream = quote! {};
let mut symbols_stream = quote! {};
let mut prefill_stream = quote! {};
let mut from_str_stream = quote! {};
let mut counter = 0u32;
let mut keys = HashSet::<String>::new();

let mut check_dup = |str: &str| {
if !keys.insert(str.to_string()) {
panic!("Symbol `{}` is duplicated", str);
}
};

for keyword in &input.keywords.0 {
let name = &keyword.name;
let value = &keyword.value;
check_dup(&value.value());
prefill_stream.extend(quote! {
#value,
});
keyword_stream.extend(quote! {
pub const #name: Keyword = Keyword {
ident: Ident::with_empty_ctxt(super::Symbol::new(#counter))
};
});
from_str_stream.extend(quote! {
#value => Ok(#name),
});
counter += 1;
}

for symbol in &input.symbols.0 {
let value = &symbol.0;
let value_str = value.to_string();
check_dup(&value_str);
prefill_stream.extend(quote! {
#value_str,
});
symbols_stream.extend(quote! {
pub const #value: Symbol = Symbol::new(#counter);
});
counter += 1;
}

TokenStream::from(quote! {
macro_rules! keywords {
() => {
#keyword_stream

impl std::str::FromStr for Keyword {
type Err = ();

fn from_str(s: &str) -> Result<Self, ()> {
match s {
#from_str_stream
_ => Err(()),
}
}
}
}
}

macro_rules! symbols {
() => {
#symbols_stream
}
}

impl Interner {
pub fn fresh() -> Self {
Interner::prefill(&[
#prefill_stream
])
}
}
})
}
12 changes: 12 additions & 0 deletions src/libsyntax/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ pub struct Path {
pub segments: Vec<PathSegment>,
}

impl PartialEq<Symbol> for Path {
fn eq(&self, symbol: &Symbol) -> bool {
self.segments.len() == 1 && {
let name = self.segments[0].ident.name;
// Make sure these symbols are pure strings
debug_assert!(!symbol.is_gensymed());
debug_assert!(!name.is_gensymed());
name == *symbol
}
}
}

impl<'a> PartialEq<&'a str> for Path {
fn eq(&self, string: &&'a str) -> bool {
self.segments.len() == 1 && self.segments[0].ident.name == *string
Expand Down
15 changes: 12 additions & 3 deletions src/libsyntax/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ impl NestedMetaItem {
}

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

Expand Down Expand Up @@ -151,7 +154,10 @@ impl Attribute {
/// attribute is marked as used.
///
/// To check the attribute name without marking it used, use the `path` field directly.
pub fn check_name(&self, name: &str) -> bool {
pub fn check_name<T>(&self, name: T) -> bool
where
Path: PartialEq<T>,
{
let matches = self.path == name;
if matches {
mark_used(self);
Expand Down Expand Up @@ -244,7 +250,10 @@ impl MetaItem {
}
}

pub fn check_name(&self, name: &str) -> bool {
pub fn check_name<T>(&self, name: T) -> bool
where
Path: PartialEq<T>,
{
self.path == name
}

Expand Down
28 changes: 14 additions & 14 deletions src/libsyntax/feature_gate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::tokenstream::TokenTree;
use errors::{DiagnosticBuilder, Handler};
use rustc_data_structures::fx::FxHashMap;
use rustc_target::spec::abi::Abi;
use syntax_pos::{Span, DUMMY_SP};
use syntax_pos::{Span, DUMMY_SP, symbols};
use log::debug;

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

if attr.check_name("doc") {
if attr.check_name(symbols::doc) {
if let Some(content) = attr.meta_item_list() {
if content.len() == 1 && content[0].check_name("cfg") {
if content.len() == 1 && content[0].check_name(symbols::cfg) {
gate_feature_post!(&self, doc_cfg, attr.span,
"#[doc(cfg(...))] is experimental"
);
} else if content.iter().any(|c| c.check_name("masked")) {
} else if content.iter().any(|c| c.check_name(symbols::masked)) {
gate_feature_post!(&self, doc_masked, attr.span,
"#[doc(masked)] is experimental"
);
} else if content.iter().any(|c| c.check_name("spotlight")) {
} else if content.iter().any(|c| c.check_name(symbols::spotlight)) {
gate_feature_post!(&self, doc_spotlight, attr.span,
"#[doc(spotlight)] is experimental"
);
} else if content.iter().any(|c| c.check_name("alias")) {
} else if content.iter().any(|c| c.check_name(symbols::alias)) {
gate_feature_post!(&self, doc_alias, attr.span,
"#[doc(alias = \"...\")] is experimental"
);
} else if content.iter().any(|c| c.check_name("keyword")) {
} else if content.iter().any(|c| c.check_name(symbols::keyword)) {
gate_feature_post!(&self, doc_keyword, attr.span,
"#[doc(keyword = \"...\")] is experimental"
);
}
}
}

match BUILTIN_ATTRIBUTES.iter().find(|(name, ..)| attr.path == name) {
match BUILTIN_ATTRIBUTES.iter().find(|(name, ..)| attr.path == *name) {
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.
Expand Down Expand Up @@ -1748,7 +1748,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ItemKind::Struct(..) => {
for attr in attr::filter_by_name(&i.attrs[..], "repr") {
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
if item.check_name("simd") {
if item.check_name(symbols::simd) {
gate_feature_post!(&self, repr_simd, attr.span,
"SIMD types are experimental and possibly buggy");
}
Expand All @@ -1759,7 +1759,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
ast::ItemKind::Enum(..) => {
for attr in attr::filter_by_name(&i.attrs[..], "repr") {
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
if item.check_name("align") {
if item.check_name(symbols::align) {
gate_feature_post!(&self, repr_align_enum, attr.span,
"`#[repr(align(x))]` on enums is experimental");
}
Expand Down Expand Up @@ -2083,7 +2083,7 @@ pub fn get_features(span_handler: &Handler, krate_attrs: &[ast::Attribute],
// Process the edition umbrella feature-gates first, to ensure
// `edition_enabled_features` is completed before it's queried.
for attr in krate_attrs {
if !attr.check_name("feature") {
if !attr.check_name(symbols::feature) {
continue
}

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

for attr in krate_attrs {
if !attr.check_name("feature") {
if !attr.check_name(symbols::feature) {
continue
}

Expand Down Expand Up @@ -2258,7 +2258,7 @@ fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate,
};
if !allow_features {
for attr in &krate.attrs {
if attr.check_name("feature") {
if attr.check_name(symbols::feature) {
let release_channel = option_env!("CFG_RELEASE_CHANNEL").unwrap_or("(unknown)");
span_err!(span_handler, attr.span, E0554,
"#![feature] may not be used on the {} release channel",
Expand Down
2 changes: 1 addition & 1 deletion src/libsyntax_ext/proc_macro_decls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub fn modify(sess: &ParseSess,
}

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

impl<'a> CollectProcMacros<'a> {
Expand Down
Loading