Auto merge of #50307 - petrochenkov:keyhyg2, r=nikomatsakis

Implement edition hygiene for keywords

Determine "keywordness" of an identifier in its hygienic context.
cc https://github.com/rust-lang/rust/pull/49611

I've resurrected `proc` as an Edition-2015-only keyword for testing purposes, but it should probably be buried again. EDIT: `proc` is removed again.
This commit is contained in:
bors 2018-05-18 10:57:05 +00:00
commit df40e61382
58 changed files with 896 additions and 119 deletions

View File

@ -818,7 +818,7 @@ impl Ident {
pub fn new_raw(string: &str, span: Span) -> Ident {
let mut ident = Ident::new(string, span);
if ident.sym == keywords::Underscore.name() ||
token::is_path_segment_keyword(ast::Ident::with_empty_ctxt(ident.sym)) {
ast::Ident::with_empty_ctxt(ident.sym).is_path_segment_keyword() {
panic!("`{:?}` is not a valid raw identifier", string)
}
ident.is_raw = true;

View File

@ -593,6 +593,7 @@ impl<'a> LoweringContext<'a> {
span: Some(span),
allow_internal_unstable: true,
allow_internal_unsafe: false,
edition: codemap::hygiene::default_edition(),
},
});
span.with_ctxt(SyntaxContext::empty().apply_mark(mark))

View File

@ -13,7 +13,7 @@ pub use self::AnnNode::*;
use rustc_target::spec::abi::Abi;
use syntax::ast;
use syntax::codemap::{CodeMap, Spanned};
use syntax::parse::{token, ParseSess};
use syntax::parse::ParseSess;
use syntax::parse::lexer::comments;
use syntax::print::pp::{self, Breaks};
use syntax::print::pp::Breaks::{Consistent, Inconsistent};
@ -1559,7 +1559,7 @@ impl<'a> State<'a> {
}
pub fn print_name(&mut self, name: ast::Name) -> io::Result<()> {
if token::is_raw_guess(ast::Ident::with_empty_ctxt(name)) {
if name.to_ident().is_raw_guess() {
self.s.word(&format!("r#{}", name))?;
} else {
self.s.word(&name.as_str())?;

View File

@ -131,6 +131,15 @@ impl_stable_hash_for!(struct ::syntax::attr::Stability {
rustc_const_unstable
});
impl<'a> HashStable<StableHashingContext<'a>>
for ::syntax::edition::Edition {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
mem::discriminant(self).hash_stable(hcx, hasher);
}
}
impl<'a> HashStable<StableHashingContext<'a>>
for ::syntax::attr::StabilityLevel {
fn hash_stable<W: StableHasherResult>(&self,
@ -389,6 +398,7 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::NameAndSpan {
format,
allow_internal_unstable,
allow_internal_unsafe,
edition,
span
});

View File

@ -34,6 +34,7 @@ use session::search_paths::PathKind;
use std::any::Any;
use std::path::{Path, PathBuf};
use syntax::ast;
use syntax::edition::Edition;
use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
use syntax_pos::Span;
@ -235,6 +236,7 @@ pub trait CrateStore {
fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol;
fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator;
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh;
fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition;
fn struct_field_names_untracked(&self, def: DefId) -> Vec<ast::Name>;
fn item_children_untracked(&self, did: DefId, sess: &Session) -> Vec<def::Export>;
fn load_macro_untracked(&self, did: DefId, sess: &Session) -> LoadedMacro;
@ -309,6 +311,7 @@ impl CrateStore for DummyCrateStore {
bug!("crate_disambiguator")
}
fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh { bug!("crate_hash") }
fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition { bug!("crate_edition_untracked") }
// resolve
fn def_key(&self, def: DefId) -> DefKey { bug!("def_key") }

View File

@ -21,7 +21,7 @@ use syntax::ext::base::ExtCtxt;
use syntax::ext::base::Resolver;
use syntax::ext::build::AstBuilder;
use syntax::ext::expand::ExpansionConfig;
use syntax::ext::hygiene::{Mark, SyntaxContext};
use syntax::ext::hygiene::{self, Mark, SyntaxContext};
use syntax::fold::{self, Folder};
use syntax::parse::ParseSess;
use syntax::ptr::P;
@ -86,6 +86,7 @@ impl<'a> Folder for ExpandAllocatorDirectives<'a> {
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
edition: hygiene::default_edition(),
},
});
let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark));

View File

@ -108,7 +108,7 @@ use syntax::ast;
use syntax::codemap::{CodeMap, FileLoader, RealFileLoader};
use syntax::feature_gate::{GatedCfg, UnstableFeatures};
use syntax::parse::{self, PResult};
use syntax_pos::{DUMMY_SP, MultiSpan, FileName};
use syntax_pos::{hygiene, DUMMY_SP, MultiSpan, FileName};
#[cfg(test)]
mod test;
@ -466,6 +466,7 @@ pub fn run_compiler<'a>(args: &[String],
};
let (sopts, cfg) = config::build_session_options_and_crate_config(&matches);
hygiene::set_default_edition(sopts.edition);
driver::spawn_thread_pool(sopts, |sopts| {
run_compiler_with_pool(matches, sopts, cfg, callbacks, file_loader, emitter_dest)

View File

@ -35,6 +35,7 @@ use std::{cmp, fs};
use syntax::ast;
use syntax::attr;
use syntax::edition::Edition;
use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
use syntax::visit;
@ -535,7 +536,10 @@ impl<'a> CrateLoader<'a> {
mem::transmute::<*mut u8, fn(&mut Registry)>(sym)
};
struct MyRegistrar(Vec<(ast::Name, Lrc<SyntaxExtension>)>);
struct MyRegistrar {
extensions: Vec<(ast::Name, Lrc<SyntaxExtension>)>,
edition: Edition,
}
impl Registry for MyRegistrar {
fn register_custom_derive(&mut self,
@ -544,36 +548,38 @@ impl<'a> CrateLoader<'a> {
attributes: &[&'static str]) {
let attrs = attributes.iter().cloned().map(Symbol::intern).collect::<Vec<_>>();
let derive = ProcMacroDerive::new(expand, attrs.clone());
let derive = SyntaxExtension::ProcMacroDerive(Box::new(derive), attrs);
self.0.push((Symbol::intern(trait_name), Lrc::new(derive)));
let derive = SyntaxExtension::ProcMacroDerive(
Box::new(derive), attrs, self.edition
);
self.extensions.push((Symbol::intern(trait_name), Lrc::new(derive)));
}
fn register_attr_proc_macro(&mut self,
name: &str,
expand: fn(TokenStream, TokenStream) -> TokenStream) {
let expand = SyntaxExtension::AttrProcMacro(
Box::new(AttrProcMacro { inner: expand })
Box::new(AttrProcMacro { inner: expand }), self.edition
);
self.0.push((Symbol::intern(name), Lrc::new(expand)));
self.extensions.push((Symbol::intern(name), Lrc::new(expand)));
}
fn register_bang_proc_macro(&mut self,
name: &str,
expand: fn(TokenStream) -> TokenStream) {
let expand = SyntaxExtension::ProcMacro(
Box::new(BangProcMacro { inner: expand })
Box::new(BangProcMacro { inner: expand }), self.edition
);
self.0.push((Symbol::intern(name), Lrc::new(expand)));
self.extensions.push((Symbol::intern(name), Lrc::new(expand)));
}
}
let mut my_registrar = MyRegistrar(Vec::new());
let mut my_registrar = MyRegistrar { extensions: Vec::new(), edition: root.edition };
registrar(&mut my_registrar);
// Intentionally leak the dynamic library. We can't ever unload it
// since the library can make things that will live arbitrarily long.
mem::forget(lib);
my_registrar.0
my_registrar.extensions
}
/// Look for a plugin registrar. Returns library path, crate

View File

@ -24,6 +24,7 @@ use rustc::util::nodemap::{FxHashMap, NodeMap};
use rustc_data_structures::sync::{Lrc, RwLock, Lock};
use syntax::{ast, attr};
use syntax::edition::Edition;
use syntax::ext::base::SyntaxExtension;
use syntax::symbol::Symbol;
use syntax_pos;
@ -234,4 +235,8 @@ impl CrateMetadata {
pub fn panic_strategy(&self) -> PanicStrategy {
self.root.panic_strategy.clone()
}
pub fn edition(&self) -> Edition {
self.root.edition
}
}

View File

@ -38,6 +38,7 @@ use std::sync::Arc;
use syntax::ast;
use syntax::attr;
use syntax::codemap;
use syntax::edition::Edition;
use syntax::ext::base::SyntaxExtension;
use syntax::parse::filemap_to_stream;
use syntax::symbol::Symbol;
@ -464,6 +465,11 @@ impl CrateStore for cstore::CStore {
self.get_crate_data(cnum).hash()
}
fn crate_edition_untracked(&self, cnum: CrateNum) -> Edition
{
self.get_crate_data(cnum).edition()
}
/// Returns the `DefKey` for a given `DefId`. This indicates the
/// parent `DefId` as well as some idea of what kind of data the
/// `DefId` refers to.
@ -512,7 +518,8 @@ impl CrateStore for cstore::CStore {
return LoadedMacro::ProcMacro(proc_macros[id.index.to_proc_macro_index()].1.clone());
} else if data.name == "proc_macro" &&
self.get_crate_data(id.krate).item_name(id.index) == "quote" {
let ext = SyntaxExtension::ProcMacro(Box::new(::proc_macro::__internal::Quoter));
let ext = SyntaxExtension::ProcMacro(Box::new(::proc_macro::__internal::Quoter),
data.edition());
return LoadedMacro::ProcMacro(Lrc::new(ext));
}

View File

@ -44,7 +44,7 @@ use syntax::ast::{self, CRATE_NODE_ID};
use syntax::codemap::Spanned;
use syntax::attr;
use syntax::symbol::Symbol;
use syntax_pos::{self, FileName, FileMap, Span, DUMMY_SP};
use syntax_pos::{self, hygiene, FileName, FileMap, Span, DUMMY_SP};
use rustc::hir::{self, PatKind};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
@ -496,6 +496,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
hash: link_meta.crate_hash,
disambiguator: tcx.sess.local_crate_disambiguator(),
panic_strategy: tcx.sess.panic_strategy(),
edition: hygiene::default_edition(),
has_global_allocator: has_global_allocator,
has_default_lib_allocator: has_default_lib_allocator,
plugin_registrar_fn: tcx.sess

View File

@ -23,6 +23,7 @@ use rustc_target::spec::{PanicStrategy, TargetTriple};
use rustc_serialize as serialize;
use syntax::{ast, attr};
use syntax::edition::Edition;
use syntax::symbol::Symbol;
use syntax_pos::{self, Span};
@ -189,6 +190,7 @@ pub struct CrateRoot {
pub hash: hir::svh::Svh,
pub disambiguator: CrateDisambiguator,
pub panic_strategy: PanicStrategy,
pub edition: Edition,
pub has_global_allocator: bool,
pub has_default_lib_allocator: bool,
pub plugin_registrar_fn: Option<DefIndex>,

View File

@ -21,7 +21,6 @@ use rustc::session::Session;
use syntax::ast::*;
use syntax::attr;
use syntax::codemap::Spanned;
use syntax::parse::token;
use syntax::symbol::keywords;
use syntax::visit::{self, Visitor};
use syntax_pos::Span;
@ -40,14 +39,13 @@ impl<'a> AstValidator<'a> {
let valid_names = [keywords::UnderscoreLifetime.name(),
keywords::StaticLifetime.name(),
keywords::Invalid.name()];
if !valid_names.contains(&ident.name) &&
token::is_reserved_ident(ident.without_first_quote()) {
if !valid_names.contains(&ident.name) && ident.without_first_quote().is_reserved() {
self.err_handler().span_err(ident.span, "lifetimes cannot use keyword names");
}
}
fn check_label(&self, ident: Ident) {
if token::is_reserved_ident(ident.without_first_quote()) {
if ident.without_first_quote().is_reserved() {
self.err_handler()
.span_err(ident.span, &format!("invalid label name `{}`", ident.name));
}

View File

@ -15,6 +15,7 @@ use rustc::session::Session;
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT, IdentTT};
use syntax::ext::base::MacroExpanderFn;
use syntax::ext::hygiene;
use syntax::symbol::Symbol;
use syntax::ast;
use syntax::feature_gate::AttributeType;
@ -107,7 +108,8 @@ impl<'a> Registry<'a> {
def_info: _,
allow_internal_unstable,
allow_internal_unsafe,
unstable_feature
unstable_feature,
edition,
} => {
let nid = ast::CRATE_NODE_ID;
NormalTT {
@ -115,7 +117,8 @@ impl<'a> Registry<'a> {
def_info: Some((nid, self.krate_span)),
allow_internal_unstable,
allow_internal_unsafe,
unstable_feature
unstable_feature,
edition,
}
}
IdentTT(ext, _, allow_internal_unstable) => {
@ -150,6 +153,7 @@ impl<'a> Registry<'a> {
allow_internal_unstable: false,
allow_internal_unsafe: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
}

View File

@ -588,7 +588,8 @@ impl<'a> Resolver<'a> {
let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
&self.session.features_untracked(),
&macro_def));
&macro_def,
self.cstore.crate_edition_untracked(def_id.krate)));
self.macro_map.insert(def_id, ext.clone());
ext
}

View File

@ -58,7 +58,6 @@ use syntax::ast::{Item, ItemKind, ImplItem, ImplItemKind};
use syntax::ast::{Label, Local, Mutability, Pat, PatKind, Path};
use syntax::ast::{QSelf, TraitItemKind, TraitRef, Ty, TyKind};
use syntax::feature_gate::{feature_err, GateIssue};
use syntax::parse::token;
use syntax::ptr::P;
use syntax_pos::{Span, DUMMY_SP, MultiSpan};
@ -3274,7 +3273,7 @@ impl<'a> Resolver<'a> {
// `$crate::a::b`
module = Some(self.resolve_crate_root(ident.span.ctxt(), true));
continue
} else if i == 1 && !token::is_path_segment_keyword(ident) {
} else if i == 1 && !ident.is_path_segment_keyword() {
let prev_name = path[0].name;
if prev_name == keywords::Extern.name() ||
prev_name == keywords::CrateRoot.name() &&

View File

@ -24,7 +24,7 @@ use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Annotatable, Determinacy, MultiModifier, MultiDecorator};
use syntax::ext::base::{MacroKind, SyntaxExtension, Resolver as SyntaxResolver};
use syntax::ext::expand::{Expansion, ExpansionKind, Invocation, InvocationKind, find_attr_invoc};
use syntax::ext::hygiene::{Mark, MarkKind};
use syntax::ext::hygiene::{self, Mark, MarkKind};
use syntax::ext::placeholders::placeholder;
use syntax::ext::tt::macro_rules;
use syntax::feature_gate::{self, emit_feature_err, GateIssue};
@ -328,7 +328,7 @@ impl<'a> base::Resolver for Resolver<'a> {
for did in self.unused_macros.iter() {
let id_span = match *self.macro_map[did] {
SyntaxExtension::NormalTT { def_info, .. } => def_info,
SyntaxExtension::DeclMacro(.., osp) => osp,
SyntaxExtension::DeclMacro(.., osp, _) => osp,
_ => None,
};
if let Some((id, span)) = id_span {
@ -371,7 +371,7 @@ impl<'a> Resolver<'a> {
};
for path in traits {
match self.resolve_macro(scope, path, MacroKind::Derive, force) {
Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs) = *ext {
Ok(ext) => if let SyntaxExtension::ProcMacroDerive(_, ref inert_attrs, _) = *ext {
if inert_attrs.contains(&attr_name) {
// FIXME(jseyfried) Avoid `mem::replace` here.
let dummy_item = placeholder(ExpansionKind::Items, ast::DUMMY_NODE_ID)
@ -755,7 +755,7 @@ impl<'a> Resolver<'a> {
let def_id = self.definitions.local_def_id(item.id);
let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess,
&self.session.features_untracked(),
item));
item, hygiene::default_edition()));
self.macro_map.insert(def_id, ext);
let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() };
@ -803,14 +803,15 @@ impl<'a> Resolver<'a> {
match *ext {
// If `ext` is a procedural macro, check if we've already warned about it
AttrProcMacro(_) | ProcMacro(_) => if !self.warned_proc_macros.insert(name) { return; },
AttrProcMacro(..) | ProcMacro(..) =>
if !self.warned_proc_macros.insert(name) { return; },
_ => return,
}
let warn_msg = match *ext {
AttrProcMacro(_) => "attribute procedural macros cannot be \
imported with `#[macro_use]`",
ProcMacro(_) => "procedural macros cannot be imported with `#[macro_use]`",
AttrProcMacro(..) => "attribute procedural macros cannot be \
imported with `#[macro_use]`",
ProcMacro(..) => "procedural macros cannot be imported with `#[macro_use]`",
_ => return,
};

View File

@ -27,7 +27,6 @@ use rustc::util::nodemap::{FxHashMap, FxHashSet};
use syntax::ast::{Ident, Name, NodeId};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::hygiene::Mark;
use syntax::parse::token;
use syntax::symbol::keywords;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::Span;
@ -667,7 +666,7 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
} else {
Some(self.resolve_crate_root(source.span.ctxt().modern(), false))
}
} else if is_extern && !token::is_path_segment_keyword(source) {
} else if is_extern && !source.is_path_segment_keyword() {
let crate_id =
self.resolver.crate_loader.process_use_extern(
source.name,
@ -715,8 +714,8 @@ impl<'a, 'b:'a> ImportResolver<'a, 'b> {
}
PathResult::Failed(span, msg, true) => {
let (mut self_path, mut self_result) = (module_path.clone(), None);
let is_special = |ident| token::is_path_segment_keyword(ident) &&
ident.name != keywords::CrateRoot.name();
let is_special = |ident: Ident| ident.is_path_segment_keyword() &&
ident.name != keywords::CrateRoot.name();
if !self_path.is_empty() && !is_special(self_path[0]) &&
!(self_path.len() > 1 && is_special(self_path[1])) {
self_path[0].name = keywords::SelfValue.name();

View File

@ -107,8 +107,7 @@ impl Path {
// or starts with something like `self`/`super`/`$crate`/etc.
pub fn make_root(&self) -> Option<PathSegment> {
if let Some(ident) = self.segments.get(0).map(|seg| seg.ident) {
if ::parse::token::is_path_segment_keyword(ident) &&
ident.name != keywords::Crate.name() {
if ident.is_path_segment_keyword() && ident.name != keywords::Crate.name() {
return None;
}
}

View File

@ -14,9 +14,10 @@ use ast::{self, Attribute, Name, PatKind, MetaItem};
use attr::HasAttrs;
use codemap::{self, CodeMap, Spanned, respan};
use syntax_pos::{Span, MultiSpan, DUMMY_SP};
use edition::Edition;
use errors::{DiagnosticBuilder, DiagnosticId};
use ext::expand::{self, Expansion, Invocation};
use ext::hygiene::{Mark, SyntaxContext};
use ext::hygiene::{self, Mark, SyntaxContext};
use fold::{self, Folder};
use parse::{self, parser, DirectoryOwnership};
use parse::token;
@ -586,13 +587,13 @@ pub enum SyntaxExtension {
MultiModifier(Box<MultiItemModifier + sync::Sync + sync::Send>),
/// A function-like procedural macro. TokenStream -> TokenStream.
ProcMacro(Box<ProcMacro + sync::Sync + sync::Send>),
ProcMacro(Box<ProcMacro + sync::Sync + sync::Send>, Edition),
/// An attribute-like procedural macro. TokenStream, TokenStream -> TokenStream.
/// The first TokenSteam is the attribute, the second is the annotated item.
/// Allows modification of the input items and adding new items, similar to
/// MultiModifier, but uses TokenStreams, rather than AST nodes.
AttrProcMacro(Box<AttrProcMacro + sync::Sync + sync::Send>),
AttrProcMacro(Box<AttrProcMacro + sync::Sync + sync::Send>, Edition),
/// A normal, function-like syntax extension.
///
@ -608,6 +609,8 @@ pub enum SyntaxExtension {
allow_internal_unsafe: bool,
/// The macro's feature name if it is unstable, and the stability feature
unstable_feature: Option<(Symbol, u32)>,
/// Edition of the crate in which the macro is defined
edition: Edition,
},
/// A function-like syntax extension that has an extra ident before
@ -619,9 +622,8 @@ pub enum SyntaxExtension {
/// The input is the annotated item.
/// Allows generating code to implement a Trait for a given struct
/// or enum item.
ProcMacroDerive(Box<MultiItemModifier +
sync::Sync +
sync::Send>, Vec<Symbol> /* inert attribute names */),
ProcMacroDerive(Box<MultiItemModifier + sync::Sync + sync::Send>,
Vec<Symbol> /* inert attribute names */, Edition),
/// An attribute-like procedural macro that derives a builtin trait.
BuiltinDerive(BuiltinDeriveFn),
@ -629,7 +631,7 @@ pub enum SyntaxExtension {
/// A declarative macro, e.g. `macro m() {}`.
///
/// The second element is the definition site span.
DeclMacro(Box<TTMacroExpander + sync::Sync + sync::Send>, Option<(ast::NodeId, Span)>),
DeclMacro(Box<TTMacroExpander + sync::Sync + sync::Send>, Option<(ast::NodeId, Span)>, Edition),
}
impl SyntaxExtension {
@ -660,6 +662,21 @@ impl SyntaxExtension {
_ => false,
}
}
pub fn edition(&self) -> Edition {
match *self {
SyntaxExtension::NormalTT { edition, .. } |
SyntaxExtension::DeclMacro(.., edition) |
SyntaxExtension::ProcMacro(.., edition) |
SyntaxExtension::AttrProcMacro(.., edition) |
SyntaxExtension::ProcMacroDerive(.., edition) => edition,
// Unstable legacy stuff
SyntaxExtension::IdentTT(..) |
SyntaxExtension::MultiDecorator(..) |
SyntaxExtension::MultiModifier(..) |
SyntaxExtension::BuiltinDerive(..) => hygiene::default_edition(),
}
}
}
pub type NamedSyntaxExtension = (Name, SyntaxExtension);

View File

@ -10,7 +10,7 @@
use attr::HasAttrs;
use ast;
use codemap::{ExpnInfo, NameAndSpan, ExpnFormat};
use codemap::{hygiene, ExpnInfo, NameAndSpan, ExpnFormat};
use ext::base::ExtCtxt;
use ext::build::AstBuilder;
use parse::parser::PathStyle;
@ -65,6 +65,7 @@ pub fn add_derived_markers<T>(cx: &mut ExtCtxt, span: Span, traits: &[ast::Path]
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
edition: hygiene::default_edition(),
},
});

View File

@ -16,7 +16,7 @@ use config::{is_test_or_bench, StripUnconfigured};
use errors::FatalError;
use ext::base::*;
use ext::derive::{add_derived_markers, collect_derives};
use ext::hygiene::{Mark, SyntaxContext};
use ext::hygiene::{self, Mark, SyntaxContext};
use ext::placeholders::{placeholder, PlaceholderExpander};
use feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err};
use fold;
@ -502,6 +502,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
span: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
edition: ext.edition(),
}
});
@ -520,7 +521,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
items.push(item);
Some(kind.expect_from_annotatables(items))
}
AttrProcMacro(ref mac) => {
AttrProcMacro(ref mac, ..) => {
self.gate_proc_macro_attr_item(attr.span, &item);
let item_tok = TokenTree::Token(DUMMY_SP, Token::interpolated(match item {
Annotatable::Item(item) => token::NtItem(item),
@ -609,7 +610,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
allow_internal_unstable,
allow_internal_unsafe,
// can't infer this type
unstable_feature: Option<(Symbol, u32)>| {
unstable_feature: Option<(Symbol, u32)>,
edition| {
// feature-gate the macro invocation
if let Some((feature, issue)) = unstable_feature {
@ -642,15 +644,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
span: def_site_span,
allow_internal_unstable,
allow_internal_unsafe,
edition,
},
});
Ok(())
};
let opt_expanded = match *ext {
DeclMacro(ref expand, def_span) => {
DeclMacro(ref expand, def_span, edition) => {
if let Err(dummy_span) = validate_and_set_expn_info(self, def_span.map(|(_, s)| s),
false, false, None) {
false, false, None,
edition) {
dummy_span
} else {
kind.make_from(expand.expand(self.cx, span, mac.node.stream()))
@ -663,11 +667,13 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
allow_internal_unstable,
allow_internal_unsafe,
unstable_feature,
edition,
} => {
if let Err(dummy_span) = validate_and_set_expn_info(self, def_info.map(|(_, s)| s),
allow_internal_unstable,
allow_internal_unsafe,
unstable_feature) {
unstable_feature,
edition) {
dummy_span
} else {
kind.make_from(expander.expand(self.cx, span, mac.node.stream()))
@ -688,6 +694,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
span: tt_span,
allow_internal_unstable,
allow_internal_unsafe: false,
edition: hygiene::default_edition(),
}
});
@ -709,7 +716,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
kind.dummy(span)
}
ProcMacro(ref expandfun) => {
ProcMacro(ref expandfun, edition) => {
if ident.name != keywords::Invalid.name() {
let msg =
format!("macro {}! expects no ident argument, given '{}'", path, ident);
@ -728,6 +735,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
// FIXME probably want to follow macro_rules macros here.
allow_internal_unstable: false,
allow_internal_unsafe: false,
edition,
},
});
@ -802,11 +810,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
span: None,
allow_internal_unstable: false,
allow_internal_unsafe: false,
edition: ext.edition(),
}
};
match *ext {
ProcMacroDerive(ref ext, _) => {
ProcMacroDerive(ref ext, ..) => {
invoc.expansion_data.mark.set_expn_info(expn_info);
let span = span.with_ctxt(self.cx.backtrace());
let dummy = ast::MetaItem { // FIXME(jseyfried) avoid this

View File

@ -10,6 +10,7 @@
use {ast, attr};
use syntax_pos::{Span, DUMMY_SP};
use edition::Edition;
use ext::base::{DummyResult, ExtCtxt, MacResult, SyntaxExtension};
use ext::base::{NormalTT, TTMacroExpander};
use ext::expand::{Expansion, ExpansionKind};
@ -183,7 +184,8 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
// Holy self-referential!
/// Converts a `macro_rules!` invocation into a syntax extension.
pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> SyntaxExtension {
pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item, edition: Edition)
-> SyntaxExtension {
let lhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("lhs"));
let rhs_nm = ast::Ident::with_empty_ctxt(Symbol::gensym("rhs"));
@ -298,10 +300,11 @@ pub fn compile(sess: &ParseSess, features: &Features, def: &ast::Item) -> Syntax
def_info: Some((def.id, def.span)),
allow_internal_unstable,
allow_internal_unsafe,
unstable_feature
unstable_feature,
edition,
}
} else {
SyntaxExtension::DeclMacro(expander, Some((def.id, def.span)))
SyntaxExtension::DeclMacro(expander, Some((def.id, def.span)), edition)
}
}

View File

@ -22,7 +22,6 @@
#![feature(unicode_internals)]
#![feature(rustc_diagnostic_macros)]
#![feature(slice_sort_by_cached_key)]
#![feature(non_exhaustive)]
#![feature(const_atomic_usize_new)]
#![feature(rustc_attrs)]
#![feature(str_escape)]
@ -142,7 +141,6 @@ pub mod codemap;
#[macro_use]
pub mod config;
pub mod entry;
pub mod edition;
pub mod feature_gate;
pub mod fold;
pub mod parse;
@ -150,6 +148,7 @@ pub mod ptr;
pub mod show_span;
pub mod std_inject;
pub mod str;
pub use syntax_pos::edition;
pub use syntax_pos::symbol;
pub mod test;
pub mod tokenstream;

View File

@ -1128,7 +1128,7 @@ impl<'a> StringReader<'a> {
return Ok(self.with_str_from(start, |string| {
// FIXME: perform NFKC normalization here. (Issue #2253)
let ident = self.mk_ident(string);
if is_raw_ident && (token::is_path_segment_keyword(ident) ||
if is_raw_ident && (ident.is_path_segment_keyword() ||
ident.name == keywords::Underscore.name()) {
self.fatal_span_(raw_start, self.pos,
&format!("`r#{}` is not currently supported.", ident.name)

View File

@ -138,44 +138,6 @@ fn ident_can_begin_type(ident: ast::Ident, is_raw: bool) -> bool {
].contains(&ident.name)
}
pub fn is_path_segment_keyword(id: ast::Ident) -> bool {
id.name == keywords::Super.name() ||
id.name == keywords::SelfValue.name() ||
id.name == keywords::SelfType.name() ||
id.name == keywords::Extern.name() ||
id.name == keywords::Crate.name() ||
id.name == keywords::CrateRoot.name() ||
id.name == keywords::DollarCrate.name()
}
// We see this identifier in a normal identifier position, like variable name or a type.
// How was it written originally? Did it use the raw form? Let's try to guess.
pub fn is_raw_guess(ident: ast::Ident) -> bool {
ident.name != keywords::Invalid.name() &&
is_reserved_ident(ident) && !is_path_segment_keyword(ident)
}
// Returns true for reserved identifiers used internally for elided lifetimes,
// unnamed method parameters, crate root module, error recovery etc.
pub fn is_special_ident(id: ast::Ident) -> bool {
id.name <= keywords::Underscore.name()
}
/// Returns `true` if the token is a keyword used in the language.
pub fn is_used_keyword(id: ast::Ident) -> bool {
id.name >= keywords::As.name() && id.name <= keywords::While.name()
}
/// Returns `true` if the token is a keyword reserved for possible future use.
pub fn is_unused_keyword(id: ast::Ident) -> bool {
id.name >= keywords::Abstract.name() && id.name <= keywords::Yield.name()
}
/// Returns `true` if the token is either a special identifier or a keyword.
pub fn is_reserved_ident(id: ast::Ident) -> bool {
is_special_ident(id) || is_used_keyword(id) || is_unused_keyword(id)
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Eq, Hash, Debug)]
pub enum Token {
/* Expression-operator symbols. */
@ -251,7 +213,7 @@ impl Token {
/// Recovers a `Token` from an `ast::Ident`. This creates a raw identifier if necessary.
pub fn from_ast_ident(ident: ast::Ident) -> Token {
Ident(ident, is_raw_guess(ident))
Ident(ident, ident.is_raw_guess())
}
/// Returns `true` if the token starts with '>'.
@ -431,7 +393,7 @@ impl Token {
pub fn is_path_segment_keyword(&self) -> bool {
match self.ident() {
Some((id, false)) => is_path_segment_keyword(id),
Some((id, false)) => id.is_path_segment_keyword(),
_ => false,
}
}
@ -440,7 +402,7 @@ impl Token {
// unnamed method parameters, crate root module, error recovery etc.
pub fn is_special_ident(&self) -> bool {
match self.ident() {
Some((id, false)) => is_special_ident(id),
Some((id, false)) => id.is_special(),
_ => false,
}
}
@ -448,7 +410,7 @@ impl Token {
/// Returns `true` if the token is a keyword used in the language.
pub fn is_used_keyword(&self) -> bool {
match self.ident() {
Some((id, false)) => is_used_keyword(id),
Some((id, false)) => id.is_used_keyword(),
_ => false,
}
}
@ -456,7 +418,7 @@ impl Token {
/// Returns `true` if the token is a keyword reserved for possible future use.
pub fn is_unused_keyword(&self) -> bool {
match self.ident() {
Some((id, false)) => is_unused_keyword(id),
Some((id, false)) => id.is_unused_keyword(),
_ => false,
}
}
@ -464,7 +426,7 @@ impl Token {
/// Returns `true` if the token is either a special identifier or a keyword.
pub fn is_reserved_ident(&self) -> bool {
match self.ident() {
Some((id, false)) => is_reserved_ident(id),
Some((id, false)) => id.is_reserved(),
_ => false,
}
}

View File

@ -2374,7 +2374,7 @@ impl<'a> State<'a> {
}
pub fn print_ident(&mut self, ident: ast::Ident) -> io::Result<()> {
if token::is_raw_guess(ident) {
if ident.is_raw_guess() {
self.s.word(&format!("r#{}", ident))?;
} else {
self.s.word(&ident.name.as_str())?;

View File

@ -14,7 +14,7 @@ use std::cell::Cell;
use ext::hygiene::{Mark, SyntaxContext};
use symbol::{Symbol, keywords};
use syntax_pos::{DUMMY_SP, Span};
use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned, respan};
use codemap::{ExpnInfo, NameAndSpan, MacroAttribute, dummy_spanned, hygiene, respan};
use ptr::P;
use tokenstream::TokenStream;
@ -30,6 +30,7 @@ fn ignored_span(sp: Span) -> Span {
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
edition: hygiene::default_edition(),
}
});
sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))

View File

@ -29,7 +29,7 @@ use entry::{self, EntryPointType};
use ext::base::{ExtCtxt, Resolver};
use ext::build::AstBuilder;
use ext::expand::ExpansionConfig;
use ext::hygiene::{Mark, SyntaxContext};
use ext::hygiene::{self, Mark, SyntaxContext};
use fold::Folder;
use feature_gate::Features;
use util::move_map::MoveMap;
@ -300,6 +300,7 @@ fn generate_test_harness(sess: &ParseSess,
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
edition: hygiene::default_edition(),
}
});

View File

@ -54,6 +54,7 @@ pub mod proc_macro_impl;
use rustc_data_structures::sync::Lrc;
use syntax::ast;
use syntax::ext::base::{MacroExpanderFn, NormalTT, NamedSyntaxExtension};
use syntax::ext::hygiene;
use syntax::symbol::Symbol;
pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
@ -74,6 +75,7 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
allow_internal_unstable: false,
allow_internal_unsafe: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
)* }
}
@ -128,7 +130,8 @@ pub fn register_builtins(resolver: &mut syntax::ext::base::Resolver,
def_info: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
unstable_feature: None
unstable_feature: None,
edition: hygiene::default_edition(),
});
for (name, ext) in user_exts {

View File

@ -14,7 +14,7 @@ use errors;
use syntax::ast::{self, Ident, NodeId};
use syntax::attr;
use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute, respan};
use syntax::codemap::{ExpnInfo, NameAndSpan, MacroAttribute, hygiene, respan};
use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder;
use syntax::ext::expand::ExpansionConfig;
@ -369,6 +369,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
span: None,
allow_internal_unstable: true,
allow_internal_unsafe: false,
edition: hygiene::default_edition(),
}
});
let span = DUMMY_SP.apply_mark(mark);

View File

@ -12,7 +12,7 @@ use std::fmt;
use std::str::FromStr;
/// The edition of the compiler (RFC 2052)
#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug)]
#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug, RustcEncodable, RustcDecodable)]
#[non_exhaustive]
pub enum Edition {
// editions must be kept in order, newest to oldest

View File

@ -17,6 +17,7 @@
use GLOBALS;
use Span;
use edition::Edition;
use symbol::{Ident, Symbol};
use serialize::{Encodable, Decodable, Encoder, Decoder};
@ -151,6 +152,7 @@ pub struct HygieneData {
syntax_contexts: Vec<SyntaxContextData>,
markings: HashMap<(SyntaxContext, Mark), SyntaxContext>,
gensym_to_ctxt: HashMap<Symbol, Span>,
default_edition: Edition,
}
impl HygieneData {
@ -168,6 +170,7 @@ impl HygieneData {
}],
markings: HashMap::new(),
gensym_to_ctxt: HashMap::new(),
default_edition: Edition::Edition2015,
}
}
@ -176,6 +179,14 @@ impl HygieneData {
}
}
pub fn default_edition() -> Edition {
HygieneData::with(|data| data.default_edition)
}
pub fn set_default_edition(edition: Edition) {
HygieneData::with(|data| data.default_edition = edition);
}
pub fn clear_markings() {
HygieneData::with(|data| data.markings = HashMap::new());
}
@ -443,6 +454,8 @@ pub struct NameAndSpan {
/// Whether the macro is allowed to use `unsafe` internally
/// even if the user crate has `#![forbid(unsafe_code)]`.
pub allow_internal_unsafe: bool,
/// Edition of the crate in which the macro is defined.
pub edition: Edition,
/// The span of the macro definition itself. The macro may not
/// have a sensible definition span (e.g. something defined
/// completely inside libsyntax) in which case this is None.

View File

@ -20,6 +20,7 @@
#![feature(const_fn)]
#![feature(custom_attribute)]
#![feature(non_exhaustive)]
#![feature(optin_builtin_traits)]
#![allow(unused_attributes)]
#![feature(specialization)]
@ -48,6 +49,7 @@ extern crate serialize as rustc_serialize; // used by deriving
extern crate unicode_width;
pub mod edition;
pub mod hygiene;
pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnFormat, NameAndSpan, CompilerDesugaringKind};
@ -298,6 +300,12 @@ impl Span {
self.ctxt().outer().expn_info().map(|i| i.call_site)
}
/// Edition of the crate from which this span came.
pub fn edition(self) -> edition::Edition {
self.ctxt().outer().expn_info().map_or_else(|| hygiene::default_edition(),
|einfo| einfo.callee.edition)
}
/// Return the source callee.
///
/// Returns None if the supplied span has no expansion trace,

View File

@ -12,6 +12,7 @@
//! allows bidirectional lookup; i.e. given a value, one can easily find the
//! type, and vice versa.
use edition::Edition;
use hygiene::SyntaxContext;
use {Span, DUMMY_SP, GLOBALS};
@ -318,7 +319,7 @@ macro_rules! declare_keywords {(
// NB: leaving holes in the ident table is bad! a different ident will get
// interned with the id from the hole, but it will be between the min and max
// of the reserved words, and thus tagged as "reserved".
// After modifying this list adjust `is_special_ident`, `is_used_keyword`/`is_unused_keyword`,
// After modifying this list adjust `is_special`, `is_used_keyword`/`is_unused_keyword`,
// this should be rarely necessary though if the keywords are kept in alphabetic order.
declare_keywords! {
// Special reserved identifiers used internally for elided lifetimes,
@ -383,16 +384,68 @@ declare_keywords! {
(53, Virtual, "virtual")
(54, Yield, "yield")
// Edition-specific keywords reserved for future use.
(55, Async, "async") // >= 2018 Edition Only
// Special lifetime names
(55, UnderscoreLifetime, "'_")
(56, StaticLifetime, "'static")
(56, UnderscoreLifetime, "'_")
(57, StaticLifetime, "'static")
// Weak keywords, have special meaning only in specific contexts.
(57, Auto, "auto")
(58, Catch, "catch")
(59, Default, "default")
(60, Dyn, "dyn")
(61, Union, "union")
(58, Auto, "auto")
(59, Catch, "catch")
(60, Default, "default")
(61, Dyn, "dyn")
(62, Union, "union")
}
impl Symbol {
fn is_unused_keyword_2018(self) -> bool {
self == keywords::Async.name()
}
}
impl Ident {
// Returns true for reserved identifiers used internally for elided lifetimes,
// unnamed method parameters, crate root module, error recovery etc.
pub fn is_special(self) -> bool {
self.name <= keywords::Underscore.name()
}
/// Returns `true` if the token is a keyword used in the language.
pub fn is_used_keyword(self) -> bool {
self.name >= keywords::As.name() && self.name <= keywords::While.name()
}
/// Returns `true` if the token is a keyword reserved for possible future use.
pub fn is_unused_keyword(self) -> bool {
// Note: `span.edition()` is relatively expensive, don't call it unless necessary.
self.name >= keywords::Abstract.name() && self.name <= keywords::Yield.name() ||
self.name.is_unused_keyword_2018() && self.span.edition() == Edition::Edition2018
}
/// Returns `true` if the token is either a special identifier or a keyword.
pub fn is_reserved(self) -> bool {
self.is_special() || self.is_used_keyword() || self.is_unused_keyword()
}
/// A keyword or reserved identifier that can be used as a path segment.
pub fn is_path_segment_keyword(self) -> bool {
self.name == keywords::Super.name() ||
self.name == keywords::SelfValue.name() ||
self.name == keywords::SelfType.name() ||
self.name == keywords::Extern.name() ||
self.name == keywords::Crate.name() ||
self.name == keywords::CrateRoot.name() ||
self.name == keywords::DollarCrate.name()
}
// We see this identifier in a normal identifier position, like variable name or a type.
// How was it written originally? Did it use the raw form? Let's try to guess.
pub fn is_raw_guess(self) -> bool {
self.name != keywords::Invalid.name() &&
self.is_reserved() && !self.is_path_segment_keyword()
}
}
// If an interner exists, return it. Otherwise, prepare a fresh one.

View File

@ -20,6 +20,7 @@ extern crate rustc_plugin;
use std::borrow::ToOwned;
use syntax::ast;
use syntax::ext::hygiene;
use syntax::ext::build::AstBuilder;
use syntax::ext::base::{TTMacroExpander, ExtCtxt, MacResult, MacEager, NormalTT};
use syntax::print::pprust;
@ -54,5 +55,6 @@ pub fn plugin_registrar(reg: &mut Registry) {
allow_internal_unstable: false,
allow_internal_unsafe: false,
unstable_feature: None,
edition: hygiene::default_edition(),
});
}

View File

@ -0,0 +1,38 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2015
#![feature(raw_identifiers)]
#[macro_export]
macro_rules! produces_async {
() => (pub fn async() {})
}
#[macro_export]
macro_rules! produces_async_raw {
() => (pub fn r#async() {})
}
#[macro_export]
macro_rules! consumes_async {
(async) => (1)
}
#[macro_export]
macro_rules! consumes_async_raw {
(r#async) => (1)
}
#[macro_export]
macro_rules! passes_ident {
($i: ident) => ($i)
}

View File

@ -0,0 +1,38 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2018
#![feature(raw_identifiers)]
#[macro_export]
macro_rules! produces_async {
() => (pub fn async() {})
}
#[macro_export]
macro_rules! produces_async_raw {
() => (pub fn r#async() {})
}
#[macro_export]
macro_rules! consumes_async {
(async) => (1)
}
#[macro_export]
macro_rules! consumes_async_raw {
(r#async) => (1)
}
#[macro_export]
macro_rules! passes_ident {
($i: ident) => ($i)
}

View File

@ -0,0 +1,43 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2015
// aux-build:edition-kw-macro-2015.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2015;
pub fn check_async() {
let mut async = 1; // OK
let mut r#async = 1; // OK
r#async = consumes_async!(async); // OK
// r#async = consumes_async!(r#async); // ERROR, not a match
// r#async = consumes_async_raw!(async); // ERROR, not a match
r#async = consumes_async_raw!(r#async); // OK
if passes_ident!(async) == 1 {} // OK
if passes_ident!(r#async) == 1 {} // OK
one_async::async(); // OK
one_async::r#async(); // OK
two_async::async(); // OK
two_async::r#async(); // OK
}
mod one_async {
produces_async! {} // OK
}
mod two_async {
produces_async_raw! {} // OK
}
fn main() {}

View File

@ -0,0 +1,43 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2015
// aux-build:edition-kw-macro-2018.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2018;
pub fn check_async() {
let mut async = 1; // OK
let mut r#async = 1; // OK
r#async = consumes_async!(async); // OK
// r#async = consumes_async!(r#async); // ERROR, not a match
// r#async = consumes_async_raw!(async); // ERROR, not a match
r#async = consumes_async_raw!(r#async); // OK
if passes_ident!(async) == 1 {} // OK
if passes_ident!(r#async) == 1 {} // OK
// one_async::async(); // ERROR, unresolved name
// one_async::r#async(); // ERROR, unresolved name
two_async::async(); // OK
two_async::r#async(); // OK
}
mod one_async {
// produces_async! {} // ERROR, reserved
}
mod two_async {
produces_async_raw! {} // OK
}
fn main() {}

View File

@ -0,0 +1,43 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2018
// aux-build:edition-kw-macro-2015.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2015;
pub fn check_async() {
// let mut async = 1; // ERROR, reserved
let mut r#async = 1; // OK
r#async = consumes_async!(async); // OK
// r#async = consumes_async!(r#async); // ERROR, not a match
// r#async = consumes_async_raw!(async); // ERROR, not a match
r#async = consumes_async_raw!(r#async); // OK
// if passes_ident!(async) == 1 {} // ERROR, reserved
if passes_ident!(r#async) == 1 {} // OK
// one_async::async(); // ERROR, reserved
one_async::r#async(); // OK
// two_async::async(); // ERROR, reserved
two_async::r#async(); // OK
}
mod one_async {
produces_async! {} // OK
}
mod two_async {
produces_async_raw! {} // OK
}
fn main() {}

View File

@ -0,0 +1,43 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2018
// aux-build:edition-kw-macro-2018.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2018;
pub fn check_async() {
// let mut async = 1; // ERROR, reserved
let mut r#async = 1; // OK
r#async = consumes_async!(async); // OK
// r#async = consumes_async!(r#async); // ERROR, not a match
// r#async = consumes_async_raw!(async); // ERROR, not a match
r#async = consumes_async_raw!(r#async); // OK
// if passes_ident!(async) == 1 {} // ERROR, reserved
if passes_ident!(r#async) == 1 {} // OK
// one_async::async(); // ERROR, reserved
// one_async::r#async(); // ERROR, unresolved name
// two_async::async(); // ERROR, reserved
two_async::r#async(); // OK
}
mod one_async {
// produces_async! {} // ERROR, reserved
}
mod two_async {
produces_async_raw! {} // OK
}
fn main() {}

View File

@ -0,0 +1,38 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2015
#![feature(raw_identifiers)]
#[macro_export]
macro_rules! produces_async {
() => (pub fn async() {})
}
#[macro_export]
macro_rules! produces_async_raw {
() => (pub fn r#async() {})
}
#[macro_export]
macro_rules! consumes_async {
(async) => (1)
}
#[macro_export]
macro_rules! consumes_async_raw {
(r#async) => (1)
}
#[macro_export]
macro_rules! passes_ident {
($i: ident) => ($i)
}

View File

@ -0,0 +1,38 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2018
#![feature(raw_identifiers)]
#[macro_export]
macro_rules! produces_async {
() => (pub fn async() {})
}
#[macro_export]
macro_rules! produces_async_raw {
() => (pub fn r#async() {})
}
#[macro_export]
macro_rules! consumes_async {
(async) => (1)
}
#[macro_export]
macro_rules! consumes_async_raw {
(r#async) => (1)
}
#[macro_export]
macro_rules! passes_ident {
($i: ident) => ($i)
}

View File

@ -0,0 +1,27 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2015
// aux-build:edition-kw-macro-2015.rs
// compile-pass
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2015;
mod one_async {
produces_async! {} // OK
}
mod two_async {
produces_async_raw! {} // OK
}
fn main() {}

View File

@ -0,0 +1,32 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2015
// aux-build:edition-kw-macro-2015.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2015;
pub fn check_async() {
let mut async = 1; // OK
let mut r#async = 1; // OK
r#async = consumes_async!(async); // OK
r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
r#async = consumes_async_raw!(r#async); // OK
if passes_ident!(async) == 1 {} // OK
if passes_ident!(r#async) == 1 {} // OK
module::async(); // OK
module::r#async(); // OK
}

View File

@ -0,0 +1,14 @@
error: no rules expected the token `r#async`
--> $DIR/edition-keywords-2015-2015-parsing.rs:24:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
| ^^^^^^^
error: no rules expected the token `async`
--> $DIR/edition-keywords-2015-2015-parsing.rs:25:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
| ^^^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,24 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2015
// aux-build:edition-kw-macro-2018.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2018;
mod one_async {
produces_async! {} // ERROR expected identifier, found reserved keyword
}
mod two_async {
produces_async_raw! {} // OK
}

View File

@ -0,0 +1,10 @@
error: expected identifier, found reserved keyword `async`
--> $DIR/edition-keywords-2015-2018-expansion.rs:20:5
|
LL | produces_async! {} // ERROR expected identifier, found reserved keyword
| ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: aborting due to previous error

View File

@ -0,0 +1,32 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2015
// aux-build:edition-kw-macro-2018.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2018;
pub fn check_async() {
let mut async = 1; // OK
let mut r#async = 1; // OK
r#async = consumes_async!(async); // OK
r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
r#async = consumes_async_raw!(r#async); // OK
if passes_ident!(async) == 1 {} // OK
if passes_ident!(r#async) == 1 {} // OK
module::async(); // OK
module::r#async(); // OK
}

View File

@ -0,0 +1,14 @@
error: no rules expected the token `r#async`
--> $DIR/edition-keywords-2015-2018-parsing.rs:24:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
| ^^^^^^^
error: no rules expected the token `async`
--> $DIR/edition-keywords-2015-2018-parsing.rs:25:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
| ^^^^^
error: aborting due to 2 previous errors

View File

@ -0,0 +1,27 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2018
// aux-build:edition-kw-macro-2015.rs
// compile-pass
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2015;
mod one_async {
produces_async! {} // OK
}
mod two_async {
produces_async_raw! {} // OK
}
fn main() {}

View File

@ -0,0 +1,32 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2018
// aux-build:edition-kw-macro-2015.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2015;
pub fn check_async() {
let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
let mut r#async = 1; // OK
r#async = consumes_async!(async); // OK
r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
r#async = consumes_async_raw!(r#async); // OK
if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
if passes_ident!(r#async) == 1 {} // OK
module::async(); //~ ERROR expected identifier, found reserved keyword `async`
module::r#async(); // OK
}

View File

@ -0,0 +1,32 @@
error: expected identifier, found reserved keyword `async`
--> $DIR/edition-keywords-2018-2015-parsing.rs:20:13
|
LL | let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
| ^^^^^ expected identifier, found reserved keyword
error: expected identifier, found reserved keyword `async`
--> $DIR/edition-keywords-2018-2015-parsing.rs:30:13
|
LL | module::async(); //~ ERROR expected identifier, found reserved keyword `async`
| ^^^^^ expected identifier, found reserved keyword
error: no rules expected the token `r#async`
--> $DIR/edition-keywords-2018-2015-parsing.rs:24:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
| ^^^^^^^
error: no rules expected the token `async`
--> $DIR/edition-keywords-2018-2015-parsing.rs:25:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
| ^^^^^
error: expected expression, found reserved keyword `async`
--> $DIR/edition-keywords-2018-2015-parsing.rs:28:22
|
LL | if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
| ^^^^^ expected expression
error: aborting due to 5 previous errors

View File

@ -0,0 +1,24 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2018
// aux-build:edition-kw-macro-2018.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2018;
mod one_async {
produces_async! {} // ERROR expected identifier, found reserved keyword `async`
}
mod two_async {
produces_async_raw! {} // OK
}

View File

@ -0,0 +1,10 @@
error: expected identifier, found reserved keyword `async`
--> $DIR/edition-keywords-2018-2018-expansion.rs:20:5
|
LL | produces_async! {} // ERROR expected identifier, found reserved keyword `async`
| ^^^^^^^^^^^^^^^^^^ expected identifier, found reserved keyword
|
= note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
error: aborting due to previous error

View File

@ -0,0 +1,32 @@
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// compile-flags: --edition=2018
// aux-build:edition-kw-macro-2018.rs
#![feature(raw_identifiers)]
#[macro_use]
extern crate edition_kw_macro_2018;
pub fn check_async() {
let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
let mut r#async = 1; // OK
r#async = consumes_async!(async); // OK
r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
r#async = consumes_async_raw!(r#async); // OK
if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
if passes_ident!(r#async) == 1 {} // OK
module::async(); //~ ERROR expected identifier, found reserved keyword `async`
module::r#async(); // OK
}

View File

@ -0,0 +1,32 @@
error: expected identifier, found reserved keyword `async`
--> $DIR/edition-keywords-2018-2018-parsing.rs:20:13
|
LL | let mut async = 1; //~ ERROR expected identifier, found reserved keyword `async`
| ^^^^^ expected identifier, found reserved keyword
error: expected identifier, found reserved keyword `async`
--> $DIR/edition-keywords-2018-2018-parsing.rs:30:13
|
LL | module::async(); //~ ERROR expected identifier, found reserved keyword `async`
| ^^^^^ expected identifier, found reserved keyword
error: no rules expected the token `r#async`
--> $DIR/edition-keywords-2018-2018-parsing.rs:24:31
|
LL | r#async = consumes_async!(r#async); //~ ERROR no rules expected the token `r#async`
| ^^^^^^^
error: no rules expected the token `async`
--> $DIR/edition-keywords-2018-2018-parsing.rs:25:35
|
LL | r#async = consumes_async_raw!(async); //~ ERROR no rules expected the token `async`
| ^^^^^
error: expected expression, found reserved keyword `async`
--> $DIR/edition-keywords-2018-2018-parsing.rs:28:22
|
LL | if passes_ident!(async) == 1 {} //~ ERROR expected expression, found reserved keyword `async`
| ^^^^^ expected expression
error: aborting due to 5 previous errors