diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index fe6909f759159..de7a3dc5ceeb2 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -138,7 +138,23 @@ impl<'a> base::Resolver for Resolver<'a> { struct EliminateCrateVar<'b, 'a: 'b>(&'b mut Resolver<'a>, Span); impl<'a, 'b> Folder for EliminateCrateVar<'a, 'b> { - fn fold_path(&mut self, mut path: ast::Path) -> ast::Path { + fn fold_path(&mut self, path: ast::Path) -> ast::Path { + match self.fold_qpath(None, path) { + (None, path) => path, + _ => unreachable!(), + } + } + + fn fold_qpath(&mut self, mut qself: Option, mut path: ast::Path) + -> (Option, ast::Path) { + qself = qself.map(|ast::QSelf { ty, path_span, position }| { + ast::QSelf { + ty: self.fold_ty(ty), + path_span: self.new_span(path_span), + position, + } + }); + let ident = path.segments[0].ident; if ident.name == keywords::DollarCrate.name() { path.segments[0].ident.name = keywords::CrateRoot.name(); @@ -150,10 +166,13 @@ impl<'a> base::Resolver for Resolver<'a> { ast::Ident::with_empty_ctxt(name).with_span_pos(span) ), _ => unreachable!(), - }) + }); + if let Some(qself) = &mut qself { + qself.position += 1; + } } } - path + (qself, path) } fn fold_mac(&mut self, mac: ast::Mac) -> ast::Mac { diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 2f209b347a4b6..1056b3dad1739 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -168,6 +168,10 @@ pub trait Folder : Sized { noop_fold_path(p, self) } + fn fold_qpath(&mut self, qs: Option, p: Path) -> (Option, Path) { + noop_fold_qpath(qs, p, self) + } + fn fold_path_parameters(&mut self, p: PathParameters) -> PathParameters { noop_fold_path_parameters(p, self) } @@ -370,14 +374,8 @@ pub fn noop_fold_ty(t: P, fld: &mut T) -> P { TyKind::Tup(tys) => TyKind::Tup(tys.move_map(|ty| fld.fold_ty(ty))), TyKind::Paren(ty) => TyKind::Paren(fld.fold_ty(ty)), TyKind::Path(qself, path) => { - let qself = qself.map(|QSelf { ty, path_span, position }| { - QSelf { - ty: fld.fold_ty(ty), - path_span: fld.new_span(path_span), - position, - } - }); - TyKind::Path(qself, fld.fold_path(path)) + let (qself, path) = fld.fold_qpath(qself, path); + TyKind::Path(qself, path) } TyKind::Array(ty, length) => { TyKind::Array(fld.fold_ty(ty), fld.fold_anon_const(length)) @@ -442,6 +440,19 @@ pub fn noop_fold_path(Path { segments, span }: Path, fld: &mut T) -> } } +pub fn noop_fold_qpath(qself: Option, + path: Path, + fld: &mut T) -> (Option, Path) { + let qself = qself.map(|QSelf { ty, path_span, position }| { + QSelf { + ty: fld.fold_ty(ty), + path_span: fld.new_span(path_span), + position, + } + }); + (qself, fld.fold_path(path)) +} + pub fn noop_fold_path_parameters(path_parameters: PathParameters, fld: &mut T) -> PathParameters { @@ -1097,15 +1108,9 @@ pub fn noop_fold_pat(p: P, folder: &mut T) -> P { PatKind::TupleStruct(folder.fold_path(pth), pats.move_map(|x| folder.fold_pat(x)), ddpos) } - PatKind::Path(opt_qself, pth) => { - let opt_qself = opt_qself.map(|qself| { - QSelf { - ty: folder.fold_ty(qself.ty), - path_span: folder.new_span(qself.path_span), - position: qself.position, - } - }); - PatKind::Path(opt_qself, folder.fold_path(pth)) + PatKind::Path(qself, pth) => { + let (qself, pth) = folder.fold_qpath(qself, pth); + PatKind::Path(qself, pth) } PatKind::Struct(pth, fields, etc) => { let pth = folder.fold_path(pth); @@ -1267,14 +1272,8 @@ pub fn noop_fold_expr(Expr {id, node, span, attrs}: Expr, folder: &mu lim) } ExprKind::Path(qself, path) => { - let qself = qself.map(|QSelf { ty, path_span, position }| { - QSelf { - ty: folder.fold_ty(ty), - path_span: folder.new_span(path_span), - position, - } - }); - ExprKind::Path(qself, folder.fold_path(path)) + let (qself, path) = folder.fold_qpath(qself, path); + ExprKind::Path(qself, path) } ExprKind::Break(opt_label, opt_expr) => { ExprKind::Break(opt_label.map(|label| folder.fold_label(label)), diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/double.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/double.rs index f4404b737f952..a6c9817f24714 100644 --- a/src/test/run-pass-fulldeps/proc-macro/auxiliary/double.rs +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/double.rs @@ -16,6 +16,8 @@ extern crate proc_macro; use proc_macro::TokenStream; +// Outputs another copy of the struct. Useful for testing the tokens +// seen by the proc_macro. #[proc_macro_derive(Double)] pub fn derive(input: TokenStream) -> TokenStream { format!("mod foo {{ {} }}", input.to_string()).parse().unwrap() diff --git a/src/test/run-pass-fulldeps/proc-macro/auxiliary/external-crate-var.rs b/src/test/run-pass-fulldeps/proc-macro/auxiliary/external-crate-var.rs new file mode 100644 index 0000000000000..030c53b3e6f32 --- /dev/null +++ b/src/test/run-pass-fulldeps/proc-macro/auxiliary/external-crate-var.rs @@ -0,0 +1,51 @@ +// Copyright 2016 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct ExternFoo; + +pub trait ExternTrait { + const CONST: u32; + type Assoc; +} + +impl ExternTrait for ExternFoo { + const CONST: u32 = 0; + type Assoc = ExternFoo; +} + +#[macro_export] +macro_rules! external { () => { + mod bar { + #[derive(Double)] + struct Bar($crate::ExternFoo); + } + + mod qself { + #[derive(Double)] + struct QSelf(<$crate::ExternFoo as $crate::ExternTrait>::Assoc); + } + + mod qself_recurse { + #[derive(Double)] + struct QSelfRecurse(< + <$crate::ExternFoo as $crate::ExternTrait>::Assoc + as $crate::ExternTrait>::Assoc + ); + } + + mod qself_in_const { + #[derive(Double)] + #[repr(u32)] + enum QSelfInConst { + Variant = <$crate::ExternFoo as $crate::ExternTrait>::CONST, + } + } +} } + diff --git a/src/test/run-pass-fulldeps/proc-macro/crate-var.rs b/src/test/run-pass-fulldeps/proc-macro/crate-var.rs index b6acb0faab2a5..41c15195bc840 100644 --- a/src/test/run-pass-fulldeps/proc-macro/crate-var.rs +++ b/src/test/run-pass-fulldeps/proc-macro/crate-var.rs @@ -9,19 +9,63 @@ // except according to those terms. // aux-build:double.rs +// aux-build:external-crate-var.rs // ignore-stage1 #![allow(unused)] #[macro_use] extern crate double; +#[macro_use] +extern crate external_crate_var; struct Foo; -macro_rules! m { () => { - #[derive(Double)] - struct Bar($crate::Foo); +trait Trait { + const CONST: u32; + type Assoc; +} + +impl Trait for Foo { + const CONST: u32 = 0; + type Assoc = Foo; +} + +macro_rules! local { () => { + // derive_Double outputs secondary copies of each definition + // to test what the proc_macro sees. + mod bar { + #[derive(Double)] + struct Bar($crate::Foo); + } + + mod qself { + #[derive(Double)] + struct QSelf(<::Foo as $crate::Trait>::Assoc); + } + + mod qself_recurse { + #[derive(Double)] + struct QSelfRecurse(<<$crate::Foo as $crate::Trait>::Assoc as $crate::Trait>::Assoc); + } + + mod qself_in_const { + #[derive(Double)] + #[repr(u32)] + enum QSelfInConst { + Variant = <::Foo as $crate::Trait>::CONST, + } + } } } -m!(); + +mod local { + local!(); +} + +// and now repeat the above tests, using a macro defined in another crate + +mod external { + external!{} +} fn main() {}