diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 63b80a3f3c1e2..ce11824042941 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -175,7 +175,7 @@ pub fn lower_crate(sess: &Session, let _ignore = dep_graph.in_ignore(); LoweringContext { - crate_root: std_inject::injected_crate_name(krate), + crate_root: std_inject::injected_crate_name(), sess, cstore, parent_def: None, diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index afca6ea2c0751..6ec7f07456a4a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -40,6 +40,7 @@ use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::parse::token::{self, Token}; +use syntax::std_inject::injected_crate_name; use syntax::symbol::keywords; use syntax::symbol::Symbol; use syntax::visit::{self, Visitor}; @@ -262,6 +263,10 @@ impl<'a> Resolver<'a> { let module = self.get_module(DefId { krate: crate_id, index: CRATE_DEF_INDEX }); self.populate_module_if_necessary(module); + if injected_crate_name().map_or(false, |name| item.ident.name == name) { + self.injected_crate = Some(module); + } + let used = self.process_legacy_macro_imports(item, module, expansion); let binding = (module, ty::Visibility::Public, sp, expansion).to_name_binding(self.arenas); @@ -561,8 +566,7 @@ impl<'a> Resolver<'a> { if let Some(id) = self.definitions.as_local_node_id(def_id) { self.local_macro_def_scopes[&id] } else if def_id.krate == BUILTIN_MACROS_CRATE { - // FIXME(jseyfried): This happens when `include!()`ing a `$crate::` path, c.f, #40469. - self.graph_root + self.injected_crate.unwrap_or(self.graph_root) } else { let module_def_id = ty::DefIdTree::parent(&*self, def_id).unwrap(); self.get_module(module_def_id) diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 49c452cddb2cd..b114c5734a5c0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1333,6 +1333,8 @@ pub struct Resolver<'a> { // Only used for better errors on `fn(): fn()` current_type_ascription: Vec, + + injected_crate: Option>, } pub struct ResolverArenas<'a> { @@ -1532,6 +1534,7 @@ impl<'a> Resolver<'a> { found_unresolved_macro: false, unused_macros: FxHashSet(), current_type_ascription: Vec::new(), + injected_crate: None, } } diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 3d1d7c0c48a1e..f6b2a8dd8611e 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -25,7 +25,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; +use syntax::ext::hygiene::{Mark, MarkKind}; use syntax::ext::placeholders::placeholder; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{self, emit_feature_err, GateIssue}; @@ -297,16 +297,19 @@ impl<'a> base::Resolver for Resolver<'a> { InvocationKind::Attr { attr: None, .. } => return Ok(None), _ => self.resolve_invoc_to_def(invoc, scope, force)?, }; + let def_id = def.def_id(); - self.macro_defs.insert(invoc.expansion_data.mark, def.def_id()); + self.macro_defs.insert(invoc.expansion_data.mark, def_id); let normal_module_def_id = self.macro_def_scope(invoc.expansion_data.mark).normal_ancestor_id; self.definitions.add_macro_def_scope(invoc.expansion_data.mark, normal_module_def_id); - self.unused_macros.remove(&def.def_id()); + self.unused_macros.remove(&def_id); let ext = self.get_macro(def); if ext.is_modern() { - invoc.expansion_data.mark.set_modern(); + invoc.expansion_data.mark.set_kind(MarkKind::Modern); + } else if def_id.krate == BUILTIN_MACROS_CRATE { + invoc.expansion_data.mark.set_kind(MarkKind::Builtin); } Ok(Some(ext)) } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 6c96692f719ff..bb1b7da7dbab2 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -21,10 +21,11 @@ use fold::{self, Folder}; use parse::{self, parser, DirectoryOwnership}; use parse::token; use ptr::P; -use symbol::Symbol; +use symbol::{keywords, Ident, Symbol}; use util::small_vector::SmallVector; use std::collections::HashMap; +use std::iter; use std::path::PathBuf; use std::rc::Rc; use std::default::Default; @@ -664,7 +665,6 @@ pub struct ExpansionData { pub struct ExtCtxt<'a> { pub parse_sess: &'a parse::ParseSess, pub ecfg: expand::ExpansionConfig<'a>, - pub crate_root: Option<&'static str>, pub root_path: PathBuf, pub resolver: &'a mut Resolver, pub resolve_err_count: usize, @@ -680,7 +680,6 @@ impl<'a> ExtCtxt<'a> { ExtCtxt { parse_sess, ecfg, - crate_root: None, root_path: PathBuf::new(), resolver, resolve_err_count: 0, @@ -822,12 +821,10 @@ impl<'a> ExtCtxt<'a> { ast::Ident::from_str(st) } pub fn std_path(&self, components: &[&str]) -> Vec { - let mut v = Vec::new(); - if let Some(s) = self.crate_root { - v.push(self.ident_of(s)); - } - v.extend(components.iter().map(|s| self.ident_of(s))); - v + let def_site = SyntaxContext::empty().apply_mark(self.current_expansion.mark); + iter::once(Ident { ctxt: def_site, ..keywords::DollarCrate.ident() }) + .chain(components.iter().map(|s| self.ident_of(s))) + .collect() } pub fn name_of(&self, st: &str) -> ast::Name { Symbol::intern(st) diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 25eef6db93036..82e7747b01461 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -319,9 +319,12 @@ impl<'a> AstBuilder for ExtCtxt<'a> { types: Vec>, bindings: Vec ) -> ast::Path { + use syntax::parse::token; + let last_identifier = idents.pop().unwrap(); let mut segments: Vec = Vec::new(); - if global { + if global && + !idents.first().map_or(false, |&ident| token::Ident(ident).is_path_segment_keyword()) { segments.push(ast::PathSegment::crate_root(span)); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 0d1b1c65a2934..ecb396f259f73 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -25,7 +25,6 @@ use parse::{DirectoryOwnership, PResult}; use parse::token::{self, Token}; use parse::parser::Parser; use ptr::P; -use std_inject; use symbol::Symbol; use symbol::keywords; use syntax_pos::{Span, DUMMY_SP}; @@ -219,7 +218,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { - self.cx.crate_root = std_inject::injected_crate_name(&krate); let mut module = ModuleData { mod_path: vec![Ident::from_str(&self.cx.ecfg.crate_name)], directory: self.cx.codemap().span_to_unmapped_path(krate.span), diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index a2d3ed4deb652..17f37d0f2c0ee 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -18,6 +18,7 @@ use util::parser::{self, AssocOp, Fixity}; use attr; use codemap::{self, CodeMap}; use syntax_pos::{self, BytePos}; +use syntax_pos::hygiene::{Mark, MarkKind, SyntaxContext}; use parse::token::{self, BinOpToken, Token}; use parse::lexer::comments; use parse::{self, ParseSess}; @@ -93,7 +94,7 @@ pub fn print_crate<'a>(cm: &'a CodeMap, is_expanded: bool) -> io::Result<()> { let mut s = State::new_from_input(cm, sess, filename, input, out, ann, is_expanded); - if is_expanded && !std_inject::injected_crate_name(krate).is_none() { + if is_expanded && !std_inject::injected_crate_name().is_none() { // We need to print `#![no_std]` (and its feature gate) so that // compiling pretty-printed source won't inject libstd again. // However we don't want these attributes in the AST because @@ -734,6 +735,8 @@ pub trait PrintState<'a> { if segment.identifier.name != keywords::CrateRoot.name() && segment.identifier.name != keywords::DollarCrate.name() { self.writer().word(&segment.identifier.name.as_str())?; + } else if segment.identifier.name == keywords::DollarCrate.name() { + self.print_dollar_crate(segment.identifier.ctxt)?; } } self.writer().space()?; @@ -822,6 +825,19 @@ pub trait PrintState<'a> { } fn nbsp(&mut self) -> io::Result<()> { self.writer().word(" ") } + + fn print_dollar_crate(&mut self, mut ctxt: SyntaxContext) -> io::Result<()> { + if let Some(mark) = ctxt.adjust(Mark::root()) { + // Make a best effort to print something that complies + if mark.kind() == MarkKind::Builtin { + if let Some(name) = std_inject::injected_crate_name() { + self.writer().word("::")?; + self.writer().word(name)?; + } + } + } + Ok(()) + } } impl<'a> PrintState<'a> for State<'a> { @@ -2411,6 +2427,8 @@ impl<'a> State<'a> { if let Some(ref parameters) = segment.parameters { self.print_path_parameters(parameters, colons_before_params)?; } + } else if segment.identifier.name == keywords::DollarCrate.name() { + self.print_dollar_crate(segment.identifier.ctxt)?; } Ok(()) } diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index ae22230198f57..00546400bb542 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -10,6 +10,7 @@ use ast; use attr; +use std::cell::Cell; use ext::hygiene::{Mark, SyntaxContext}; use symbol::{Symbol, keywords}; use syntax_pos::{DUMMY_SP, Span}; @@ -34,22 +35,25 @@ fn ignored_span(sp: Span) -> Span { sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } -pub fn injected_crate_name(krate: &ast::Crate) -> Option<&'static str> { - if attr::contains_name(&krate.attrs, "no_core") { - None - } else if attr::contains_name(&krate.attrs, "no_std") { - Some("core") - } else { - Some("std") - } +pub fn injected_crate_name() -> Option<&'static str> { + INJECTED_CRATE_NAME.with(|name| name.get()) +} + +thread_local! { + static INJECTED_CRATE_NAME: Cell> = Cell::new(None); } pub fn maybe_inject_crates_ref(mut krate: ast::Crate, alt_std_name: Option) -> ast::Crate { - let name = match injected_crate_name(&krate) { - Some(name) => name, - None => return krate, + let name = if attr::contains_name(&krate.attrs, "no_core") { + return krate; + } else if attr::contains_name(&krate.attrs, "no_std") { + "core" + } else { + "std" }; + INJECTED_CRATE_NAME.with(|opt_name| opt_name.set(Some(name))); + let crate_name = Symbol::intern(&alt_std_name.unwrap_or_else(|| name.to_string())); krate.module.items.insert(0, P(ast::Item { diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index a4ac5826f99c1..9f097169d973e 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -272,7 +272,7 @@ fn generate_test_harness(sess: &ParseSess, let mark = Mark::fresh(Mark::root()); - let mut cx: TestCtxt = TestCtxt { + let cx = TestCtxt { span_diagnostic: sd, ext_cx: ExtCtxt::new(sess, ExpansionConfig::default("test".to_string()), resolver), path: Vec::new(), @@ -283,7 +283,6 @@ fn generate_test_harness(sess: &ParseSess, toplevel_reexport: None, ctxt: SyntaxContext::empty().apply_mark(mark), }; - cx.ext_cx.crate_root = Some("std"); mark.set_expn_info(ExpnInfo { call_site: DUMMY_SP, diff --git a/src/libsyntax_ext/deriving/bounds.rs b/src/libsyntax_ext/deriving/bounds.rs index 0bc802283fb68..7f03001d9c6eb 100644 --- a/src/libsyntax_ext/deriving/bounds.rs +++ b/src/libsyntax_ext/deriving/bounds.rs @@ -8,9 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use deriving::path_std; use deriving::generic::*; use deriving::generic::ty::*; - use syntax::ast::MetaItem; use syntax::ext::base::{Annotatable, ExtCtxt}; use syntax_pos::Span; @@ -28,15 +28,10 @@ pub fn expand_deriving_copy(cx: &mut ExtCtxt, mitem: &MetaItem, item: &Annotatable, push: &mut FnMut(Annotatable)) { - let mut v = cx.crate_root.map(|s| vec![s]).unwrap_or(Vec::new()); - v.push("marker"); - v.push("Copy"); - let path = Path::new(v); - let trait_def = TraitDef { span, attributes: Vec::new(), - path, + path: path_std!(cx, marker::Copy), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/clone.rs b/src/libsyntax_ext/deriving/clone.rs index 5d93c2a5f72a1..35def632fc188 100644 --- a/src/libsyntax_ext/deriving/clone.rs +++ b/src/libsyntax_ext/deriving/clone.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use deriving::path_std; use deriving::generic::*; use deriving::generic::ty::*; @@ -55,7 +56,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, })); } ItemKind::Union(..) => { - bounds = vec![Literal(path_std!(cx, core::marker::Copy))]; + bounds = vec![Literal(path_std!(cx, marker::Copy))]; is_shallow = true; substructure = combine_substructure(Box::new(|c, s, sub| { cs_clone_shallow("Clone", c, s, sub, true) @@ -79,7 +80,7 @@ pub fn expand_deriving_clone(cx: &mut ExtCtxt, let trait_def = TraitDef { span, attributes: Vec::new(), - path: path_std!(cx, core::clone::Clone), + path: path_std!(cx, clone::Clone), additional_bounds: bounds, generics: LifetimeBounds::empty(), is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/cmp/eq.rs b/src/libsyntax_ext/deriving/cmp/eq.rs index a282ff5bd045f..237c8654edf6e 100644 --- a/src/libsyntax_ext/deriving/cmp/eq.rs +++ b/src/libsyntax_ext/deriving/cmp/eq.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use deriving::path_std; use deriving::generic::*; use deriving::generic::ty::*; @@ -30,7 +31,7 @@ pub fn expand_deriving_eq(cx: &mut ExtCtxt, let trait_def = TraitDef { span, attributes: Vec::new(), - path: path_std!(cx, core::cmp::Eq), + path: path_std!(cx, cmp::Eq), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/cmp/ord.rs b/src/libsyntax_ext/deriving/cmp/ord.rs index 9b057aaceceb5..1a392ac376537 100644 --- a/src/libsyntax_ext/deriving/cmp/ord.rs +++ b/src/libsyntax_ext/deriving/cmp/ord.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use deriving::path_std; use deriving::generic::*; use deriving::generic::ty::*; @@ -28,7 +29,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, let trait_def = TraitDef { span, attributes: Vec::new(), - path: path_std!(cx, core::cmp::Ord), + path: path_std!(cx, cmp::Ord), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, @@ -38,7 +39,7 @@ pub fn expand_deriving_ord(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec![borrowed_self()], - ret_ty: Literal(path_std!(cx, core::cmp::Ordering)), + ret_ty: Literal(path_std!(cx, cmp::Ordering)), attributes: attrs, is_unsafe: false, unify_fieldless_variants: true, diff --git a/src/libsyntax_ext/deriving/cmp/partial_eq.rs b/src/libsyntax_ext/deriving/cmp/partial_eq.rs index e635c6bebcd6d..75db7cc1e4c07 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_eq.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_eq.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use deriving::{path_local, path_std}; use deriving::generic::*; use deriving::generic::ty::*; @@ -93,7 +94,7 @@ pub fn expand_deriving_partial_eq(cx: &mut ExtCtxt, let trait_def = TraitDef { span, attributes: Vec::new(), - path: path_std!(cx, core::cmp::PartialEq), + path: path_std!(cx, cmp::PartialEq), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/cmp/partial_ord.rs b/src/libsyntax_ext/deriving/cmp/partial_ord.rs index e7e1c108760ab..92183c58eb269 100644 --- a/src/libsyntax_ext/deriving/cmp/partial_ord.rs +++ b/src/libsyntax_ext/deriving/cmp/partial_ord.rs @@ -10,6 +10,7 @@ pub use self::OrderingOp::*; +use deriving::{path_local, pathvec_std, path_std}; use deriving::generic::*; use deriving::generic::ty::*; @@ -45,11 +46,11 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, } } } - let ordering_ty = Literal(path_std!(cx, core::cmp::Ordering)); - let ret_ty = Literal(Path::new_(pathvec_std!(cx, core::option::Option), + let ordering_ty = Literal(path_std!(cx, cmp::Ordering)); + let ret_ty = Literal(Path::new_(pathvec_std!(cx, option::Option), None, vec![Box::new(ordering_ty)], - true)); + PathKind::Std)); let inline = cx.meta_word(span, Symbol::intern("inline")); let attrs = vec![cx.attribute(span, inline)]; @@ -84,7 +85,7 @@ pub fn expand_deriving_partial_ord(cx: &mut ExtCtxt, let trait_def = TraitDef { span, attributes: vec![], - path: path_std!(cx, core::cmp::PartialOrd), + path: path_std!(cx, cmp::PartialOrd), additional_bounds: vec![], generics: LifetimeBounds::empty(), is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/debug.rs b/src/libsyntax_ext/deriving/debug.rs index ab6dd04520c1b..82fc09fca69af 100644 --- a/src/libsyntax_ext/deriving/debug.rs +++ b/src/libsyntax_ext/deriving/debug.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use deriving::path_std; use deriving::generic::*; use deriving::generic::ty::*; @@ -24,13 +25,13 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt, item: &Annotatable, push: &mut FnMut(Annotatable)) { // &mut ::std::fmt::Formatter - let fmtr = Ptr(Box::new(Literal(path_std!(cx, core::fmt::Formatter))), + let fmtr = Ptr(Box::new(Literal(path_std!(cx, fmt::Formatter))), Borrowed(None, ast::Mutability::Mutable)); let trait_def = TraitDef { span, attributes: Vec::new(), - path: path_std!(cx, core::fmt::Debug), + path: path_std!(cx, fmt::Debug), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, @@ -40,7 +41,7 @@ pub fn expand_deriving_debug(cx: &mut ExtCtxt, generics: LifetimeBounds::empty(), explicit_self: borrowed_explicit_self(), args: vec![fmtr], - ret_ty: Literal(path_std!(cx, core::fmt::Result)), + ret_ty: Literal(path_std!(cx, fmt::Result)), attributes: Vec::new(), is_unsafe: false, unify_fieldless_variants: false, diff --git a/src/libsyntax_ext/deriving/decodable.rs b/src/libsyntax_ext/deriving/decodable.rs index 517221af1d4ba..46dada256b820 100644 --- a/src/libsyntax_ext/deriving/decodable.rs +++ b/src/libsyntax_ext/deriving/decodable.rs @@ -10,7 +10,7 @@ //! The compiler code necessary for `#[derive(Decodable)]`. See encodable.rs for more. -use deriving; +use deriving::{self, pathvec_std}; use deriving::generic::*; use deriving::generic::ty::*; use deriving::warn_if_deprecated; @@ -46,20 +46,12 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, item: &Annotatable, push: &mut FnMut(Annotatable), krate: &'static str) { - if cx.crate_root != Some("std") { - // FIXME(#21880): lift this requirement. - cx.span_err(span, - "this trait cannot be derived with #![no_std] \ - or #![no_core]"); - return; - } - let typaram = &*deriving::hygienic_type_parameter(item, "__D"); let trait_def = TraitDef { span, attributes: Vec::new(), - path: Path::new_(vec![krate, "Decodable"], None, vec![], true), + path: Path::new_(vec![krate, "Decodable"], None, vec![], PathKind::Global), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, @@ -72,18 +64,18 @@ fn expand_deriving_decodable_imp(cx: &mut ExtCtxt, vec![Path::new_(vec![krate, "Decoder"], None, vec![], - true)])], + PathKind::Global)])], }, explicit_self: None, args: vec![Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mutable))], ret_ty: - Literal(Path::new_(pathvec_std!(cx, core::result::Result), + Literal(Path::new_(pathvec_std!(cx, result::Result), None, vec![Box::new(Self_), Box::new(Literal(Path::new_( - vec![typaram, "Error"], None, vec![], false + vec![typaram, "Error"], None, vec![], PathKind::Local )))], - true)), + PathKind::Std)), attributes: Vec::new(), is_unsafe: false, unify_fieldless_variants: false, diff --git a/src/libsyntax_ext/deriving/default.rs b/src/libsyntax_ext/deriving/default.rs index 0c8e3c3939576..99e7bb4baeff4 100644 --- a/src/libsyntax_ext/deriving/default.rs +++ b/src/libsyntax_ext/deriving/default.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use deriving::path_std; use deriving::generic::*; use deriving::generic::ty::*; @@ -28,7 +29,7 @@ pub fn expand_deriving_default(cx: &mut ExtCtxt, let trait_def = TraitDef { span, attributes: Vec::new(), - path: path_std!(cx, core::default::Default), + path: path_std!(cx, default::Default), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/encodable.rs b/src/libsyntax_ext/deriving/encodable.rs index c2c862f043f24..0e6e96438d817 100644 --- a/src/libsyntax_ext/deriving/encodable.rs +++ b/src/libsyntax_ext/deriving/encodable.rs @@ -92,7 +92,7 @@ //! } //! ``` -use deriving; +use deriving::{self, pathvec_std}; use deriving::generic::*; use deriving::generic::ty::*; use deriving::warn_if_deprecated; @@ -127,20 +127,12 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, item: &Annotatable, push: &mut FnMut(Annotatable), krate: &'static str) { - if cx.crate_root != Some("std") { - // FIXME(#21880): lift this requirement. - cx.span_err(span, - "this trait cannot be derived with #![no_std] \ - or #![no_core]"); - return; - } - let typaram = &*deriving::hygienic_type_parameter(item, "__S"); let trait_def = TraitDef { span, attributes: Vec::new(), - path: Path::new_(vec![krate, "Encodable"], None, vec![], true), + path: Path::new_(vec![krate, "Encodable"], None, vec![], PathKind::Global), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, @@ -150,19 +142,21 @@ fn expand_deriving_encodable_imp(cx: &mut ExtCtxt, name: "encode", generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec![(typaram, - vec![Path::new_(vec![krate, "Encoder"], None, vec![], true)])] + bounds: vec![ + (typaram, + vec![Path::new_(vec![krate, "Encoder"], None, vec![], PathKind::Global)]) + ], }, explicit_self: borrowed_explicit_self(), args: vec![Ptr(Box::new(Literal(Path::new_local(typaram))), Borrowed(None, Mutability::Mutable))], ret_ty: Literal(Path::new_( - pathvec_std!(cx, core::result::Result), + pathvec_std!(cx, result::Result), None, vec![Box::new(Tuple(Vec::new())), Box::new(Literal(Path::new_( - vec![typaram, "Error"], None, vec![], false + vec![typaram, "Error"], None, vec![], PathKind::Local )))], - true + PathKind::Std )), attributes: Vec::new(), is_unsafe: false, diff --git a/src/libsyntax_ext/deriving/generic/ty.rs b/src/libsyntax_ext/deriving/generic/ty.rs index 47b5f40832ac0..e4faf652389a0 100644 --- a/src/libsyntax_ext/deriving/generic/ty.rs +++ b/src/libsyntax_ext/deriving/generic/ty.rs @@ -21,6 +21,8 @@ use syntax::ext::build::AstBuilder; use syntax::codemap::respan; use syntax::ptr::P; use syntax_pos::Span; +use syntax_pos::hygiene::SyntaxContext; +use syntax_pos::symbol::keywords; /// The types of pointers #[derive(Clone, Eq, PartialEq)] @@ -36,29 +38,36 @@ pub enum PtrTy<'a> { /// for type parameters and a lifetime. #[derive(Clone, Eq, PartialEq)] pub struct Path<'a> { - pub path: Vec<&'a str>, - pub lifetime: Option<&'a str>, - pub params: Vec>>, - pub global: bool, + path: Vec<&'a str>, + lifetime: Option<&'a str>, + params: Vec>>, + kind: PathKind, +} + +#[derive(Clone, Eq, PartialEq)] +pub enum PathKind { + Local, + Global, + Std, } impl<'a> Path<'a> { pub fn new<'r>(path: Vec<&'r str>) -> Path<'r> { - Path::new_(path, None, Vec::new(), true) + Path::new_(path, None, Vec::new(), PathKind::Std) } pub fn new_local<'r>(path: &'r str) -> Path<'r> { - Path::new_(vec![path], None, Vec::new(), false) + Path::new_(vec![path], None, Vec::new(), PathKind::Local) } pub fn new_<'r>(path: Vec<&'r str>, lifetime: Option<&'r str>, params: Vec>>, - global: bool) + kind: PathKind) -> Path<'r> { Path { path, lifetime, params, - global, + kind, } } @@ -76,11 +85,20 @@ impl<'a> Path<'a> { self_ty: Ident, self_generics: &Generics) -> ast::Path { - let idents = self.path.iter().map(|s| cx.ident_of(*s)).collect(); + let mut idents = self.path.iter().map(|s| cx.ident_of(*s)).collect(); let lt = mk_lifetimes(cx, span, &self.lifetime); let tys = self.params.iter().map(|t| t.to_ty(cx, span, self_ty, self_generics)).collect(); - cx.path_all(span, self.global, idents, lt, tys, Vec::new()) + match self.kind { + PathKind::Global => cx.path_all(span, true, idents, lt, tys, Vec::new()), + PathKind::Local => cx.path_all(span, false, idents, lt, tys, Vec::new()), + PathKind::Std => { + let def_site = SyntaxContext::empty().apply_mark(cx.current_expansion.mark); + idents.insert(0, Ident { ctxt: def_site, ..keywords::DollarCrate.ident() }); + cx.path_all(span, false, idents, lt, tys, Vec::new()) + } + } + } } diff --git a/src/libsyntax_ext/deriving/hash.rs b/src/libsyntax_ext/deriving/hash.rs index 6c78eea186d61..b192ab2527e4b 100644 --- a/src/libsyntax_ext/deriving/hash.rs +++ b/src/libsyntax_ext/deriving/hash.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use deriving; +use deriving::{self, pathvec_std, path_std}; use deriving::generic::*; use deriving::generic::ty::*; @@ -24,7 +24,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, item: &Annotatable, push: &mut FnMut(Annotatable)) { - let path = Path::new_(pathvec_std!(cx, core::hash::Hash), None, vec![], true); + let path = Path::new_(pathvec_std!(cx, hash::Hash), None, vec![], PathKind::Std); let typaram = &*deriving::hygienic_type_parameter(item, "__H"); @@ -41,7 +41,7 @@ pub fn expand_deriving_hash(cx: &mut ExtCtxt, name: "hash", generics: LifetimeBounds { lifetimes: Vec::new(), - bounds: vec![(typaram, vec![path_std!(cx, core::hash::Hasher)])], + bounds: vec![(typaram, vec![path_std!(cx, hash::Hasher)])], }, explicit_self: borrowed_explicit_self(), args: vec![Ptr(Box::new(Literal(arg)), diff --git a/src/libsyntax_ext/deriving/mod.rs b/src/libsyntax_ext/deriving/mod.rs index ccf3d5502341f..a6696b533694e 100644 --- a/src/libsyntax_ext/deriving/mod.rs +++ b/src/libsyntax_ext/deriving/mod.rs @@ -19,32 +19,16 @@ use syntax::ptr::P; use syntax::symbol::Symbol; use syntax_pos::Span; -macro_rules! pathvec { - ($($x:ident)::+) => ( - vec![ $( stringify!($x) ),+ ] - ) +macro path_local($x:ident) { + generic::ty::Path::new_local(stringify!($x)) } -macro_rules! path_local { - ($x:ident) => ( - ::deriving::generic::ty::Path::new_local(stringify!($x)) - ) -} - -macro_rules! pathvec_std { - ($cx:expr, $first:ident :: $($rest:ident)::+) => ({ - let mut v = pathvec![$($rest)::+]; - if let Some(s) = $cx.crate_root { - v.insert(0, s); - } - v - }) -} +macro pathvec_std($cx:expr, $($rest:ident)::+) {{ + vec![ $( stringify!($rest) ),+ ] +}} -macro_rules! path_std { - ($($x:tt)*) => ( - ::deriving::generic::ty::Path::new( pathvec_std!( $($x)* ) ) - ) +macro path_std($($x:tt)*) { + generic::ty::Path::new( pathvec_std!( $($x)* ) ) } pub mod bounds; diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 42bbb4ae0cbee..82d6ee5afa05b 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -16,6 +16,7 @@ #![deny(warnings)] #![feature(proc_macro_internals)] +#![feature(decl_macro)] extern crate fmt_macros; #[macro_use] diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 9358e654a9fc8..ab6c3f7d62d76 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -27,7 +27,7 @@ use std::fmt; #[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] pub struct SyntaxContext(pub(super) u32); -#[derive(Copy, Clone, Default)] +#[derive(Copy, Clone)] pub struct SyntaxContextData { pub outer_mark: Mark, pub prev_ctxt: SyntaxContext, @@ -35,20 +35,26 @@ pub struct SyntaxContextData { } /// A mark is a unique id associated with a macro expansion. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] pub struct Mark(u32); -#[derive(Default)] struct MarkData { parent: Mark, - modern: bool, + kind: MarkKind, expn_info: Option, } +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum MarkKind { + Modern, + Builtin, + Legacy, +} + impl Mark { pub fn fresh(parent: Mark) -> Self { HygieneData::with(|data| { - data.marks.push(MarkData { parent: parent, modern: false, expn_info: None }); + data.marks.push(MarkData { parent: parent, kind: MarkKind::Legacy, expn_info: None }); Mark(data.marks.len() as u32 - 1) }) } @@ -77,7 +83,7 @@ impl Mark { pub fn modern(mut self) -> Mark { HygieneData::with(|data| { loop { - if self == Mark::root() || data.marks[self.0 as usize].modern { + if self == Mark::root() || data.marks[self.0 as usize].kind == MarkKind::Modern { return self; } self = data.marks[self.0 as usize].parent; @@ -85,12 +91,12 @@ impl Mark { }) } - pub fn is_modern(self) -> bool { - HygieneData::with(|data| data.marks[self.0 as usize].modern) + pub fn kind(self) -> MarkKind { + HygieneData::with(|data| data.marks[self.0 as usize].kind) } - pub fn set_modern(self) { - HygieneData::with(|data| data.marks[self.0 as usize].modern = true) + pub fn set_kind(self, kind: MarkKind) { + HygieneData::with(|data| data.marks[self.0 as usize].kind = kind) } pub fn is_descendant_of(mut self, ancestor: Mark) -> bool { @@ -116,8 +122,16 @@ struct HygieneData { impl HygieneData { fn new() -> Self { HygieneData { - marks: vec![MarkData::default()], - syntax_contexts: vec![SyntaxContextData::default()], + marks: vec![MarkData { + parent: Mark::root(), + kind: MarkKind::Builtin, + expn_info: None, + }], + syntax_contexts: vec![SyntaxContextData { + outer_mark: Mark::root(), + prev_ctxt: SyntaxContext(0), + modern: SyntaxContext(0), + }], markings: HashMap::new(), gensym_to_ctxt: HashMap::new(), } @@ -150,7 +164,7 @@ impl SyntaxContext { HygieneData::with(|data| { data.marks.push(MarkData { parent: Mark::root(), - modern: false, + kind: MarkKind::Legacy, expn_info: Some(expansion_info) }); @@ -170,7 +184,7 @@ impl SyntaxContext { HygieneData::with(|data| { let syntax_contexts = &mut data.syntax_contexts; let mut modern = syntax_contexts[self.0 as usize].modern; - if data.marks[mark.0 as usize].modern { + if data.marks[mark.0 as usize].kind == MarkKind::Modern { modern = *data.markings.entry((modern, mark)).or_insert_with(|| { let len = syntax_contexts.len() as u32; syntax_contexts.push(SyntaxContextData { diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 02b8425d88bee..81518b0b87271 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -40,7 +40,7 @@ ((::fmt::format as - for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1 + for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((<::fmt::Arguments>::new_v1 as fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})((&([("test" as diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs index 63dbd4d5bed04..f485982e2d3bc 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_partial_eq.rs @@ -69,7 +69,7 @@ fn expand_deriving_partial_eq(cx: &mut ExtCtxt, span: Span, mitem: &MetaItem, it let trait_def = TraitDef { span: span, attributes: Vec::new(), - path: deriving::generic::ty::Path::new(vec!["std", "cmp", "PartialEq"]), + path: deriving::generic::ty::Path::new(vec!["cmp", "PartialEq"]), additional_bounds: Vec::new(), generics: LifetimeBounds::empty(), is_unsafe: false, diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs index 16856d3041749..449cd29ada3e0 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin.rs @@ -50,7 +50,7 @@ fn expand(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: vec![], - path: Path::new(vec!["TotalSum"]), + path: Path::new_local("TotalSum"), additional_bounds: vec![], generics: LifetimeBounds::empty(), associated_types: vec![], diff --git a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs index 50b16a0e26fb4..1a9358f22bfce 100644 --- a/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs +++ b/src/test/run-pass-fulldeps/auxiliary/custom_derive_plugin_attr.rs @@ -46,7 +46,7 @@ fn expand(cx: &mut ExtCtxt, let trait_def = TraitDef { span: span, attributes: vec![], - path: Path::new(vec!["TotalSum"]), + path: Path::new_local("TotalSum"), additional_bounds: vec![], generics: LifetimeBounds::empty(), associated_types: vec![], diff --git a/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs b/src/test/run-pass-fulldeps/derive-no-std-not-supported.rs similarity index 80% rename from src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs rename to src/test/run-pass-fulldeps/derive-no-std-not-supported.rs index 1e97cb07f8960..a0747e0fbf59f 100644 --- a/src/test/compile-fail-fulldeps/derive-no-std-not-supported.rs +++ b/src/test/run-pass-fulldeps/derive-no-std-not-supported.rs @@ -8,22 +8,22 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![feature(rustc_private)] #![no_std] extern crate serialize as rustc_serialize; -#[derive(RustcEncodable)] //~ ERROR this trait cannot be derived +#[derive(RustcEncodable)] struct Bar { x: u32, } -#[derive(RustcDecodable)] //~ ERROR this trait cannot be derived +#[derive(RustcDecodable)] struct Baz { x: u32, } fn main() { - Foo { x: 0 }; Bar { x: 0 }; Baz { x: 0 }; }