From 30b27f350ccca8f2b08b54b256f7e1fdb8c8ddb0 Mon Sep 17 00:00:00 2001 From: Andrew Champion Date: Sat, 8 Jun 2019 16:26:34 +0100 Subject: [PATCH 01/37] core: check for pointer equality when comparing Eq slices Because Eq types must be reflexively equal, an equal-length slice to the same memory location must be equal. --- src/libcore/slice/mod.rs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index 0e782bef39dd8..f972d13f7c391 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5304,6 +5304,29 @@ impl SlicePartialEq for [A] } } +// Use an equal-pointer optimization when types are `Eq` +impl SlicePartialEq for [A] + where A: PartialEq + Eq +{ + default fn equal(&self, other: &[A]) -> bool { + if self.len() != other.len() { + return false; + } + + if self.as_ptr() == other.as_ptr() { + return true; + } + + for i in 0..self.len() { + if !self[i].eq(&other[i]) { + return false; + } + } + + true + } +} + // Use memcmp for bytewise equality when the types allow impl SlicePartialEq for [A] where A: PartialEq + BytewiseEquality @@ -5409,7 +5432,7 @@ impl SliceOrd for [u8] { #[doc(hidden)] /// Trait implemented for types that can be compared for equality using /// their bytewise representation -trait BytewiseEquality { } +trait BytewiseEquality: Eq + Copy { } macro_rules! impl_marker_for { ($traitname:ident, $($ty:ty)*) => { From d482589f292abda9a5c2895adf63189168f92a70 Mon Sep 17 00:00:00 2001 From: Andrew Champion Date: Sat, 8 Jun 2019 20:16:50 +0100 Subject: [PATCH 02/37] core: use iterators for slice equality comparison --- src/libcore/slice/mod.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/libcore/slice/mod.rs b/src/libcore/slice/mod.rs index f972d13f7c391..ea4ea956e59a8 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5294,13 +5294,7 @@ impl SlicePartialEq for [A] return false; } - for i in 0..self.len() { - if !self[i].eq(&other[i]) { - return false; - } - } - - true + self.iter().zip(other.iter()).all(|(x, y)| x == y) } } @@ -5317,13 +5311,7 @@ impl SlicePartialEq for [A] return true; } - for i in 0..self.len() { - if !self[i].eq(&other[i]) { - return false; - } - } - - true + self.iter().zip(other.iter()).all(|(x, y)| x == y) } } From 45dda939ab558b244d9099798047ec6e6376cff1 Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Mon, 1 Jul 2019 22:18:45 +0800 Subject: [PATCH 03/37] Move async-await tests from run-pass to ui --- src/test/{run-pass => ui}/async-await/async-fn-size.rs | 5 +++-- src/test/{run-pass => ui}/async-await/issue-60709.rs | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) rename src/test/{run-pass => ui}/async-await/async-fn-size.rs (98%) rename src/test/{run-pass => ui}/async-await/issue-60709.rs (98%) diff --git a/src/test/run-pass/async-await/async-fn-size.rs b/src/test/ui/async-await/async-fn-size.rs similarity index 98% rename from src/test/run-pass/async-await/async-fn-size.rs rename to src/test/ui/async-await/async-fn-size.rs index 7396918196c08..e4dfd4d829e69 100644 --- a/src/test/run-pass/async-await/async-fn-size.rs +++ b/src/test/ui/async-await/async-fn-size.rs @@ -1,9 +1,10 @@ +// run-pass + // edition:2018 #![feature(async_await)] -#[path = "../auxiliary/arc_wake.rs"] -mod arc_wake; +extern crate arc_wake; use std::pin::Pin; use std::future::Future; diff --git a/src/test/run-pass/async-await/issue-60709.rs b/src/test/ui/async-await/issue-60709.rs similarity index 98% rename from src/test/run-pass/async-await/issue-60709.rs rename to src/test/ui/async-await/issue-60709.rs index 5ebb18b999ab6..ad0b49fa4a219 100644 --- a/src/test/run-pass/async-await/issue-60709.rs +++ b/src/test/ui/async-await/issue-60709.rs @@ -2,6 +2,8 @@ // handled incorrectly in generators. // compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018 +// run-pass + #![feature(async_await)] #![allow(unused)] From b14a2ec400aa58a71a8e69a05f8bb41f3b571c2b Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Wed, 3 Jul 2019 22:37:33 +0800 Subject: [PATCH 04/37] Remove duplicated arc_wake.rs The auxiliary file arc_wake.rs is in run-pass/auxiliary and also ui/async-await/auxiliary. Remove the former one as their contents are same. Move run-pass/futures-api.rs to ui/async-await/futures-api.rs as it needs to use arc_wake.rs. --- src/test/run-pass/auxiliary/arc_wake.rs | 64 ------------------- .../async-await}/futures-api.rs | 2 + 2 files changed, 2 insertions(+), 64 deletions(-) delete mode 100644 src/test/run-pass/auxiliary/arc_wake.rs rename src/test/{run-pass => ui/async-await}/futures-api.rs (98%) diff --git a/src/test/run-pass/auxiliary/arc_wake.rs b/src/test/run-pass/auxiliary/arc_wake.rs deleted file mode 100644 index c21886f26f467..0000000000000 --- a/src/test/run-pass/auxiliary/arc_wake.rs +++ /dev/null @@ -1,64 +0,0 @@ -// edition:2018 - -use std::sync::Arc; -use std::task::{ - Waker, RawWaker, RawWakerVTable, -}; - -macro_rules! waker_vtable { - ($ty:ident) => { - &RawWakerVTable::new( - clone_arc_raw::<$ty>, - wake_arc_raw::<$ty>, - wake_by_ref_arc_raw::<$ty>, - drop_arc_raw::<$ty>, - ) - }; -} - -pub trait ArcWake { - fn wake(self: Arc); - - fn wake_by_ref(arc_self: &Arc) { - arc_self.clone().wake() - } - - fn into_waker(wake: Arc) -> Waker where Self: Sized - { - let ptr = Arc::into_raw(wake) as *const (); - - unsafe { - Waker::from_raw(RawWaker::new(ptr, waker_vtable!(Self))) - } - } -} - -unsafe fn increase_refcount(data: *const ()) { - // Retain Arc by creating a copy - let arc: Arc = Arc::from_raw(data as *const T); - let arc_clone = arc.clone(); - // Forget the Arcs again, so that the refcount isn't decrased - let _ = Arc::into_raw(arc); - let _ = Arc::into_raw(arc_clone); -} - -unsafe fn clone_arc_raw(data: *const ()) -> RawWaker { - increase_refcount::(data); - RawWaker::new(data, waker_vtable!(T)) -} - -unsafe fn drop_arc_raw(data: *const ()) { - // Drop Arc - let _: Arc = Arc::from_raw(data as *const T); -} - -unsafe fn wake_arc_raw(data: *const ()) { - let arc: Arc = Arc::from_raw(data as *const T); - ArcWake::wake(arc); -} - -unsafe fn wake_by_ref_arc_raw(data: *const ()) { - let arc: Arc = Arc::from_raw(data as *const T); - ArcWake::wake_by_ref(&arc); - let _ = Arc::into_raw(arc); -} diff --git a/src/test/run-pass/futures-api.rs b/src/test/ui/async-await/futures-api.rs similarity index 98% rename from src/test/run-pass/futures-api.rs rename to src/test/ui/async-await/futures-api.rs index ee77053fd5b6a..a7da058de3081 100644 --- a/src/test/run-pass/futures-api.rs +++ b/src/test/ui/async-await/futures-api.rs @@ -1,3 +1,5 @@ +// run-pass + // aux-build:arc_wake.rs extern crate arc_wake; From 73aee89b47972da57b0f0b1c99ba4e2893ad0a20 Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Wed, 3 Jul 2019 23:10:03 +0800 Subject: [PATCH 05/37] Move the test async-fn-size-moved-locals to ui --- .../{run-pass => ui}/async-await/async-fn-size-moved-locals.rs | 2 ++ 1 file changed, 2 insertions(+) rename src/test/{run-pass => ui}/async-await/async-fn-size-moved-locals.rs (99%) diff --git a/src/test/run-pass/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs similarity index 99% rename from src/test/run-pass/async-await/async-fn-size-moved-locals.rs rename to src/test/ui/async-await/async-fn-size-moved-locals.rs index 139be7fe0132b..8d24ffe7a7c8c 100644 --- a/src/test/run-pass/async-await/async-fn-size-moved-locals.rs +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -7,6 +7,8 @@ // // See issue #59123 for a full explanation. +// run-pass + // edition:2018 #![feature(async_await)] From f115147fc481a4431116be526ce4dec315b1f871 Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Thu, 4 Jul 2019 21:04:20 +0800 Subject: [PATCH 06/37] Add missing aux-build directive --- src/test/ui/async-await/async-fn-size.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/async-await/async-fn-size.rs b/src/test/ui/async-await/async-fn-size.rs index e4dfd4d829e69..c6b2ed13b0a8d 100644 --- a/src/test/ui/async-await/async-fn-size.rs +++ b/src/test/ui/async-await/async-fn-size.rs @@ -1,5 +1,5 @@ // run-pass - +// aux-build:arc_wake.rs // edition:2018 #![feature(async_await)] From 70e8ba38b66ae2a52c67664eb10cfea5341b40da Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 10 Jul 2019 16:27:39 +0900 Subject: [PATCH 07/37] Fix typo in libcore/intrinsics.rs --- src/libcore/intrinsics.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 67430e5bbda4d..513e22a788cdf 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -705,7 +705,8 @@ extern "rust-intrinsic" { they should be used through stabilized interfaces \ in the rest of the standard library", issue = "0")] - #[rustc_deprecated(reason = "no longer used by rustc, will be removed - use MaybeUnint instead", + #[rustc_deprecated(reason = "no longer used by rustc, will be removed - use MaybeUninit \ + instead", since = "1.38.0")] pub fn init() -> T; From 128143c4e505aae88b7c6cde38aa7dab19e1e47c Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Wed, 10 Jul 2019 21:18:51 +0800 Subject: [PATCH 08/37] Ignore async-fn-size-moved-locals test on wasm The sizes for wasm are different. Co-Authored-By: Tyler Mandry --- src/test/ui/async-await/async-fn-size-moved-locals.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs index 8d24ffe7a7c8c..d0d4eb032fcb1 100644 --- a/src/test/ui/async-await/async-fn-size-moved-locals.rs +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -7,6 +7,7 @@ // // See issue #59123 for a full explanation. +// ignore-wasm32-bare (sizes don't match) // run-pass // edition:2018 From 6031a07a464eae202cc43fbb15fada094171488d Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Sat, 6 Jul 2019 00:51:19 +1000 Subject: [PATCH 09/37] filedesc: don't use ioctl(FIOCLEX) on Linux All ioctl(2)s will fail on O_PATH file descriptors on Linux (because they use &empty_fops as a security measure against O_PATH descriptors affecting the backing file). As a result, File::try_clone() and various other methods would always fail with -EBADF on O_PATH file descriptors. The solution is to simply use F_SETFD (as is used on other unices) which works on O_PATH descriptors because it operates through the fnctl(2) layer and not through ioctl(2)s. Since this code is usually only used in strange error paths (a broken or ancient kernel), the extra overhead of one syscall shouldn't cause any dramas. Most other systems programming languages also use the fnctl(2) so this brings us in line with them. Fixes: rust-lang/rust#62314 Signed-off-by: Aleksa Sarai --- src/libstd/sys/unix/fd.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 6d23963e141aa..0cecdd7ffa0b7 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -175,6 +175,7 @@ impl FileDesc { target_os = "emscripten", target_os = "fuchsia", target_os = "l4re", + target_os = "linux", target_os = "haiku")))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -187,6 +188,7 @@ impl FileDesc { target_os = "emscripten", target_os = "fuchsia", target_os = "l4re", + target_os = "linux", target_os = "haiku"))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { From fa0809d3cdacae8638fd7beea2e85310902e21d3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 9 Jul 2019 11:15:05 +0200 Subject: [PATCH 10/37] Regression test for issue 30786. --- src/test/ui/hrtb/issue-30786.migrate.stderr | 11 ++ src/test/ui/hrtb/issue-30786.nll.stderr | 14 +++ src/test/ui/hrtb/issue-30786.rs | 115 ++++++++++++++++++++ 3 files changed, 140 insertions(+) create mode 100644 src/test/ui/hrtb/issue-30786.migrate.stderr create mode 100644 src/test/ui/hrtb/issue-30786.nll.stderr create mode 100644 src/test/ui/hrtb/issue-30786.rs diff --git a/src/test/ui/hrtb/issue-30786.migrate.stderr b/src/test/ui/hrtb/issue-30786.migrate.stderr new file mode 100644 index 0000000000000..9a4f877282245 --- /dev/null +++ b/src/test/ui/hrtb/issue-30786.migrate.stderr @@ -0,0 +1,11 @@ +error: implementation of `Stream` is not general enough + --> $DIR/issue-30786.rs:107:22 + | +LL | let map = source.map(|x: &_| x); + | ^^^ + | + = note: `Stream` would have to be implemented for the type `&'0 mut Map`, for any lifetime `'0` + = note: but `Stream` is actually implemented for the type `&'1 mut Map`, for some specific lifetime `'1` + +error: aborting due to previous error + diff --git a/src/test/ui/hrtb/issue-30786.nll.stderr b/src/test/ui/hrtb/issue-30786.nll.stderr new file mode 100644 index 0000000000000..5c865d76851d3 --- /dev/null +++ b/src/test/ui/hrtb/issue-30786.nll.stderr @@ -0,0 +1,14 @@ +error: higher-ranked subtype error + --> $DIR/issue-30786.rs:111:18 + | +LL | let filter = map.filter(|x: &_| true); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: higher-ranked subtype error + --> $DIR/issue-30786.rs:113:17 + | +LL | let count = filter.count(); // Assert that we still have a valid stream. + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/hrtb/issue-30786.rs b/src/test/ui/hrtb/issue-30786.rs new file mode 100644 index 0000000000000..321b83c3459d0 --- /dev/null +++ b/src/test/ui/hrtb/issue-30786.rs @@ -0,0 +1,115 @@ +// rust-lang/rust#30786: the use of `for<'b> &'b mut A: Stream Option; +} + +// Example stream +pub struct Repeat(u64); + +impl<'a> Stream for &'a mut Repeat { + type Item = &'a u64; + fn next(self) -> Option { + Some(&self.0) + } +} + +pub struct Map { + stream: S, + func: F, +} + +impl<'a, A, F, T> Stream for &'a mut Map +where &'a mut A: Stream, + F: FnMut(<&'a mut A as Stream>::Item) -> T, +{ + type Item = T; + fn next(self) -> Option { + match self.stream.next() { + Some(item) => Some((self.func)(item)), + None => None, + } + } +} + +pub struct Filter { + stream: S, + func: F, +} + +impl<'a, A, F, T> Stream for &'a mut Filter +where for<'b> &'b mut A: Stream, // <---- BAD + F: FnMut(&T) -> bool, +{ + type Item = <&'a mut A as Stream>::Item; + fn next(self) -> Option { + while let Some(item) = self.stream.next() { + if (self.func)(&item) { + return Some(item); + } + } + None + } +} + +pub trait StreamExt where for<'b> &'b mut Self: Stream { + fn map(self, func: F) -> Map + where Self: Sized, + for<'a> &'a mut Map: Stream, + { + Map { + func: func, + stream: self, + } + } + + fn filter(self, func: F) -> Filter + where Self: Sized, + for<'a> &'a mut Filter: Stream, + { + Filter { + func: func, + stream: self, + } + } + + fn count(mut self) -> usize + where Self: Sized, + { + let mut count = 0; + while let Some(_) = self.next() { + count += 1; + } + count + } +} + +impl StreamExt for T where for<'a> &'a mut T: Stream { } + +fn main() { + let source = Repeat(10); + let map = source.map(|x: &_| x); + //[migrate]~^ ERROR implementation of `Stream` is not general enough + //[migrate]~| NOTE `Stream` would have to be implemented for the type `&'0 mut Map + //[migrate]~| NOTE but `Stream` is actually implemented for the type `&'1 + let filter = map.filter(|x: &_| true); + //[nll]~^ ERROR higher-ranked subtype error + let count = filter.count(); // Assert that we still have a valid stream. + //[nll]~^ ERROR higher-ranked subtype error +} From 48635226d8d71f18b09ea40f5cdbe34dbaaf378f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 18 Jun 2019 22:23:13 +0300 Subject: [PATCH 11/37] Remove `MacroKind::ProcMacroStub` It's internal to resolve and always results in `Res::Err` outside of resolve. Instead put `DefKind::Fn`s themselves into the macro namespace, it's ok. Proc macro stubs are items placed into macro namespase for functions that define proc macros. https://github.com/rust-lang/rust/pull/52383 The rustdoc test is changed because the old test didn't actually reproduce the ICE it was supposed to reproduce. --- src/librustc/ich/impls_syntax.rs | 1 - src/librustc_resolve/build_reduced_graph.rs | 36 +++++++++---------- src/librustc_resolve/macros.rs | 21 ++++++----- src/librustdoc/clean/mod.rs | 1 - src/librustdoc/html/item_type.rs | 1 - src/librustdoc/html/render.rs | 2 -- .../passes/collect_intra_doc_links.rs | 14 +++----- src/librustdoc/visit_ast.rs | 7 ++-- src/libsyntax/ext/base.rs | 3 -- src/test/rustdoc/proc-macro.rs | 2 +- 10 files changed, 35 insertions(+), 53 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 1db18d3028258..c09b2003f3867 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -89,7 +89,6 @@ impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { Bang, Attr, Derive, - ProcMacroStub, }); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 49116f3f171e2..974487ab9d2d7 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -29,7 +29,7 @@ use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant}; -use syntax::ext::base::{MacroKind, SyntaxExtension}; +use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; @@ -46,6 +46,20 @@ use log::debug; type Res = def::Res; +fn proc_macro_stub(item: &Item) -> Option<(Ident, Span)> { + if attr::contains_name(&item.attrs, sym::proc_macro) || + attr::contains_name(&item.attrs, sym::proc_macro_attribute) { + return Some((item.ident, item.span)); + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { + if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { + if let Some(ident) = nested_meta.ident() { + return Some((ident, ident.span)); + } + } + } + None +} + impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { @@ -456,22 +470,8 @@ impl<'a> Resolver<'a> { // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). - if attr::contains_name(&item.attrs, sym::proc_macro) || - attr::contains_name(&item.attrs, sym::proc_macro_attribute) { - let res = Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), res.def_id()); - self.define(parent, ident, MacroNS, (res, vis, sp, expansion)); - } - if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(trait_attr) = - attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = trait_attr.ident() { - let res = Res::Def( - DefKind::Macro(MacroKind::ProcMacroStub), - res.def_id(), - ); - self.define(parent, ident, MacroNS, (res, vis, ident.span, expansion)); - } - } + if let Some((ident, span)) = proc_macro_stub(item) { + self.define(parent, ident, MacroNS, (res, vis, span, expansion)); } } @@ -778,8 +778,6 @@ impl<'a> Resolver<'a> { crate fn opt_get_macro(&mut self, res: Res) -> Option> { let def_id = match res { - Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) => - return Some(self.non_macro_attr(true)), // some dummy extension Res::Def(DefKind::Macro(..), def_id) => def_id, Res::NonMacroAttr(attr_kind) => return Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 8f23c9813f7d9..a3e00bcb81a9f 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -102,12 +102,11 @@ fn sub_namespace_match(candidate: Option, requirement: Option Some(SubNS::Bang), - MacroKind::Attr | MacroKind::Derive => Some(SubNS::AttrLike), - MacroKind::ProcMacroStub => None, + MacroKind::Bang => SubNS::Bang, + MacroKind::Attr | MacroKind::Derive => SubNS::AttrLike, }; - let requirement = requirement.and_then(|kind| sub_ns(kind)); - let candidate = candidate.and_then(|kind| sub_ns(kind)); + let candidate = candidate.map(sub_ns); + let requirement = requirement.map(sub_ns); // "No specific sub-namespace" means "matches anything" for both requirements and candidates. candidate.is_none() || requirement.is_none() || candidate == requirement } @@ -310,15 +309,15 @@ impl<'a> Resolver<'a> { let res = res?; match res { - Res::Def(DefKind::Macro(macro_kind), def_id) => { + Res::Def(DefKind::Macro(_), def_id) => { if let Some(node_id) = self.definitions.as_local_node_id(def_id) { self.unused_macros.remove(&node_id); } - if macro_kind == MacroKind::ProcMacroStub { - let msg = "can't use a procedural macro from the same crate that defines it"; - self.session.span_err(path.span, msg); - return Err(Determinacy::Determined); - } + } + Res::Def(DefKind::Fn, _) => { + let msg = "can't use a procedural macro from the same crate that defines it"; + self.session.span_err(path.span, msg); + return Err(Determinacy::Determined); } Res::NonMacroAttr(attr_kind) => { if kind == MacroKind::Attr { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 350bcc9dbc649..72e6614dc0652 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -4199,7 +4199,6 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { MacroKind::Bang => (i, TypeKind::Macro), MacroKind::Attr => (i, TypeKind::Attr), MacroKind::Derive => (i, TypeKind::Derive), - MacroKind::ProcMacroStub => unreachable!(), }, Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias), Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), diff --git a/src/librustdoc/html/item_type.rs b/src/librustdoc/html/item_type.rs index 5f1a1b31616c1..9affc08141d09 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -92,7 +92,6 @@ impl<'a> From<&'a clean::Item> for ItemType { MacroKind::Bang => ItemType::Macro, MacroKind::Attr => ItemType::ProcAttribute, MacroKind::Derive => ItemType::ProcDerive, - MacroKind::ProcMacroStub => unreachable!(), } clean::StrippedItem(..) => unreachable!(), } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2d69c29dfae3c..5c6847b414136 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2471,7 +2471,6 @@ impl<'a> fmt::Display for Item<'a> { MacroKind::Bang => write!(fmt, "Macro ")?, MacroKind::Attr => write!(fmt, "Attribute Macro ")?, MacroKind::Derive => write!(fmt, "Derive Macro ")?, - MacroKind::ProcMacroStub => unreachable!(), } clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?, @@ -5092,7 +5091,6 @@ fn item_proc_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, m } write!(w, "")?; } - _ => {} } document(w, cx, it) } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index bb85fe898dabd..acf7a951856ea 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -429,15 +429,11 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { let segment = ast::PathSegment::from_ident(Ident::from_str(path_str)); let path = ast::Path { segments: vec![segment], span: DUMMY_SP }; cx.enter_resolver(|resolver| { - let parent_scope = resolver.dummy_parent_scope(); - if let Ok(res) = resolver.resolve_macro_to_res_inner(&path, MacroKind::Bang, - &parent_scope, false, false) { - if let Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) = res { - // skip proc-macro stubs, they'll cause `get_macro` to crash - } else { - if let SyntaxExtensionKind::LegacyBang(..) = resolver.get_macro(res).kind { - return Some(res.map_id(|_| panic!("unexpected id"))); - } + if let Ok(res @ Res::Def(DefKind::Macro(_), _)) = resolver.resolve_macro_to_res_inner( + &path, MacroKind::Bang, &resolver.dummy_parent_scope(), false, false + ) { + if let SyntaxExtensionKind::LegacyBang { .. } = resolver.get_macro(res).kind { + return Some(res.map_id(|_| panic!("unexpected id"))); } } if let Some(res) = resolver.all_macros.get(&Symbol::intern(path_str)) { diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index fa5faaf3ff568..009d681ed8353 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -406,11 +406,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // Struct and variant constructors and proc macro stubs always show up alongside // their definitions, we've already processed them so just discard these. - match path.res { - Res::Def(DefKind::Ctor(..), _) - | Res::SelfCtor(..) - | Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) => return, - _ => {} + if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = path.res { + return; } // If there was a private module in the current path then don't bother inlining diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index c0ba41b8af405..8d5e4a3369e7c 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -527,8 +527,6 @@ pub enum MacroKind { Attr, /// A derive attribute macro - #[derive(Foo)] Derive, - /// A view of a procedural macro from the same crate that defines it. - ProcMacroStub, } impl MacroKind { @@ -537,7 +535,6 @@ impl MacroKind { MacroKind::Bang => "macro", MacroKind::Attr => "attribute macro", MacroKind::Derive => "derive macro", - MacroKind::ProcMacroStub => "crate-local procedural macro", } } diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs index 1e396f1be0e04..4bd0b092b55a7 100644 --- a/src/test/rustdoc/proc-macro.rs +++ b/src/test/rustdoc/proc-macro.rs @@ -7,7 +7,7 @@ // @has some_macros/index.html // @has - '//a/[@href="attr.some_proc_attr.html"]' 'some_proc_attr' -//! include a link to [some_proc_attr] to make sure it works. +//! include a link to [some_proc_macro] to make sure it works. extern crate proc_macro; From ec376c783e3a64445c4b55fb5980ae922319a916 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 19 Jun 2019 01:00:49 +0300 Subject: [PATCH 12/37] Move `MacroKind` into `libsyntax_pos` So it can be eventually used in `ExpnInfo` --- src/libsyntax/ext/base.rs | 29 +---------------------------- src/libsyntax_pos/hygiene.rs | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 8d5e4a3369e7c..09ff44115b49d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -24,6 +24,7 @@ use std::path::PathBuf; use std::rc::Rc; use std::default::Default; +pub use syntax_pos::hygiene::MacroKind; #[derive(Debug,Clone)] pub enum Annotatable { @@ -518,34 +519,6 @@ impl MacResult for DummyResult { } } -/// Represents different kinds of macro invocations that can be resolved. -#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum MacroKind { - /// A bang macro - foo!() - Bang, - /// An attribute macro - #[foo] - Attr, - /// A derive attribute macro - #[derive(Foo)] - Derive, -} - -impl MacroKind { - pub fn descr(self) -> &'static str { - match self { - MacroKind::Bang => "macro", - MacroKind::Attr => "attribute macro", - MacroKind::Derive => "derive macro", - } - } - - pub fn article(self) -> &'static str { - match self { - MacroKind::Attr => "an", - _ => "a", - } - } -} - /// A syntax extension kind. pub enum SyntaxExtensionKind { /// A token-based function-like macro. diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index f52952ca40274..6a2aba17a793e 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -723,6 +723,34 @@ impl ExpnFormat { } } +/// The kind of macro invocation or definition. +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum MacroKind { + /// A bang macro `foo!()`. + Bang, + /// An attribute macro `#[foo]`. + Attr, + /// A derive macro `#[derive(Foo)]` + Derive, +} + +impl MacroKind { + pub fn descr(self) -> &'static str { + match self { + MacroKind::Bang => "macro", + MacroKind::Attr => "attribute macro", + MacroKind::Derive => "derive macro", + } + } + + pub fn article(self) -> &'static str { + match self { + MacroKind::Attr => "an", + _ => "a", + } + } +} + /// The kind of compiler desugaring. #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum CompilerDesugaringKind { From 16918a8e28d4e7a476f31ff3d3c1e2d998c086af Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 19 Jun 2019 01:08:45 +0300 Subject: [PATCH 13/37] Rename some things in `syntax_pos/hygiene` More consistent with other naming: ExpnFormat -> ExpnKind ExpnKind::name -> ExpnKind::descr DesugaringKind::name -> DesugaringKind::descr Shorter, no tautology: CompilerDesugaring -> Desugaring CompilerDesugaringKind -> DesugaringKind --- src/librustc/hir/lowering.rs | 35 ++++++++------- src/librustc/ich/impls_syntax.rs | 8 ++-- .../infer/error_reporting/need_type_info.rs | 6 +-- src/librustc/lint/internal.rs | 4 +- src/librustc/lint/mod.rs | 16 +++---- src/librustc/mir/mod.rs | 2 +- src/librustc/traits/error_reporting.rs | 8 ++-- src/librustc_allocator/expand.rs | 5 ++- src/librustc_borrowck/borrowck/mod.rs | 6 +-- .../borrow_check/conflict_errors.rs | 4 +- src/librustc_mir/borrow_check/mod.rs | 2 +- src/librustc_save_analysis/lib.rs | 5 +-- src/librustc_typeck/check/_match.rs | 4 +- src/librustc_typeck/check/mod.rs | 4 +- src/libsyntax/ext/base.rs | 14 +++--- src/libsyntax/ext/derive.rs | 4 +- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/source_map.rs | 4 +- src/libsyntax/std_inject.rs | 4 +- src/libsyntax/test.rs | 4 +- src/libsyntax_ext/proc_macro_decls.rs | 4 +- src/libsyntax_ext/test.rs | 4 +- src/libsyntax_ext/test_case.rs | 4 +- src/libsyntax_pos/hygiene.rs | 44 +++++++++---------- src/libsyntax_pos/lib.rs | 24 +++++----- 25 files changed, 111 insertions(+), 110 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 2a9fd58f84b3b..549c34d961aa4 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -62,8 +62,7 @@ use syntax::ast::*; use syntax::errors; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::print::pprust; -use syntax::source_map::{self, respan, ExpnInfo, CompilerDesugaringKind, Spanned}; -use syntax::source_map::CompilerDesugaringKind::CondTemporary; +use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned}; use syntax::std_inject; use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; @@ -872,7 +871,7 @@ impl<'a> LoweringContext<'a> { /// allowed inside this span. fn mark_span_with_reason( &self, - reason: CompilerDesugaringKind, + reason: DesugaringKind, span: Span, allow_internal_unstable: Option>, ) -> Span { @@ -880,7 +879,7 @@ impl<'a> LoweringContext<'a> { mark.set_expn_info(ExpnInfo { def_site: Some(span), allow_internal_unstable, - ..ExpnInfo::default(source_map::CompilerDesugaring(reason), span, self.sess.edition()) + ..ExpnInfo::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) }); span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } @@ -1188,7 +1187,7 @@ impl<'a> LoweringContext<'a> { }; let unstable_span = self.mark_span_with_reason( - CompilerDesugaringKind::Async, + DesugaringKind::Async, span, self.allow_gen_future.clone(), ); @@ -1733,7 +1732,7 @@ impl<'a> LoweringContext<'a> { // Not tracking it makes lints in rustc and clippy very fragile, as // frequently opened issues show. let exist_ty_span = self.mark_span_with_reason( - CompilerDesugaringKind::ExistentialType, + DesugaringKind::ExistentialType, span, None, ); @@ -2603,7 +2602,7 @@ impl<'a> LoweringContext<'a> { let span = output.span(); let exist_ty_span = self.mark_span_with_reason( - CompilerDesugaringKind::Async, + DesugaringKind::Async, span, None, ); @@ -3275,7 +3274,7 @@ impl<'a> LoweringContext<'a> { }; let desugared_span = - this.mark_span_with_reason(CompilerDesugaringKind::Async, span, None); + this.mark_span_with_reason(DesugaringKind::Async, span, None); // Construct an argument representing `__argN: ` to replace the argument of the // async function. @@ -4410,7 +4409,9 @@ impl<'a> LoweringContext<'a> { _ => { // Lower condition: let cond = self.lower_expr(cond); - let span_block = self.mark_span_with_reason(CondTemporary, cond.span, None); + let span_block = self.mark_span_with_reason( + DesugaringKind::CondTemporary, cond.span, None + ); // Wrap in a construct equivalent to `{ let _t = $cond; _t }` // to preserve drop semantics since `if cond { ... }` does not // let temporaries live outside of `cond`. @@ -4469,7 +4470,9 @@ impl<'a> LoweringContext<'a> { // Lower condition: let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond)); - let span_block = this.mark_span_with_reason(CondTemporary, cond.span, None); + let span_block = this.mark_span_with_reason( + DesugaringKind::CondTemporary, cond.span, None + ); // Wrap in a construct equivalent to `{ let _t = $cond; _t }` // to preserve drop semantics since `while cond { ... }` does not // let temporaries live outside of `cond`. @@ -4508,7 +4511,7 @@ impl<'a> LoweringContext<'a> { ExprKind::TryBlock(ref body) => { self.with_catch_scope(body.id, |this| { let unstable_span = this.mark_span_with_reason( - CompilerDesugaringKind::TryBlock, + DesugaringKind::TryBlock, body.span, this.allow_try_trait.clone(), ); @@ -4836,7 +4839,7 @@ impl<'a> LoweringContext<'a> { let mut head = self.lower_expr(head); let head_sp = head.span; let desugared_span = self.mark_span_with_reason( - CompilerDesugaringKind::ForLoop, + DesugaringKind::ForLoop, head_sp, None, ); @@ -4990,13 +4993,13 @@ impl<'a> LoweringContext<'a> { // } let unstable_span = self.mark_span_with_reason( - CompilerDesugaringKind::QuestionMark, + DesugaringKind::QuestionMark, e.span, self.allow_try_trait.clone(), ); let try_span = self.sess.source_map().end_point(e.span); let try_span = self.mark_span_with_reason( - CompilerDesugaringKind::QuestionMark, + DesugaringKind::QuestionMark, try_span, self.allow_try_trait.clone(), ); @@ -5811,12 +5814,12 @@ impl<'a> LoweringContext<'a> { } } let span = self.mark_span_with_reason( - CompilerDesugaringKind::Await, + DesugaringKind::Await, await_span, None, ); let gen_future_span = self.mark_span_with_reason( - CompilerDesugaringKind::Await, + DesugaringKind::Await, await_span, self.allow_gen_future.clone(), ); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c09b2003f3867..f679a65c642f9 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -398,7 +398,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::Transparency { impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { call_site, - format, + kind, def_site, default_transparency, allow_internal_unstable, @@ -407,13 +407,13 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { edition }); -impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { +impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind { MacroAttribute(sym), MacroBang(sym), - CompilerDesugaring(kind) + Desugaring(kind) }); -impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { +impl_stable_hash_for!(enum ::syntax_pos::hygiene::DesugaringKind { CondTemporary, Async, Await, diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 4426b5c0e85b5..770d5155777bb 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -5,7 +5,7 @@ use crate::infer::InferCtxt; use crate::infer::type_variable::TypeVariableOriginKind; use crate::ty::{self, Ty, Infer, TyVar}; use crate::ty::print::Print; -use syntax::source_map::CompilerDesugaringKind; +use syntax::source_map::DesugaringKind; use syntax_pos::Span; use errors::DiagnosticBuilder; @@ -194,12 +194,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { )); } else if let Some(pattern) = local_visitor.found_local_pattern { if let Some(simple_ident) = pattern.simple_ident() { - match pattern.span.compiler_desugaring_kind() { + match pattern.span.desugaring_kind() { None => labels.push(( pattern.span, format!("consider giving `{}` {}", simple_ident, suffix), )), - Some(CompilerDesugaringKind::ForLoop) => labels.push(( + Some(DesugaringKind::ForLoop) => labels.push(( pattern.span, "the element type for this iterator is not specified".to_owned(), )), diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs index 3489973694967..0b514f5927d30 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -247,10 +247,10 @@ impl EarlyLintPass for LintPassImpl { } fn is_lint_pass_expansion(expn_info: &ExpnInfo) -> bool { - if expn_info.format.name() == sym::impl_lint_pass { + if expn_info.kind.descr() == sym::impl_lint_pass { true } else if let Some(info) = expn_info.call_site.ctxt().outer_expn_info() { - info.format.name() == sym::declare_lint_pass + info.kind.descr() == sym::declare_lint_pass } else { false } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 59b08b832d272..2bf4f1d3cfbba 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -35,7 +35,7 @@ use crate::util::nodemap::NodeMap; use errors::{DiagnosticBuilder, DiagnosticId}; use std::{hash, ptr}; use syntax::ast; -use syntax::source_map::{MultiSpan, ExpnFormat, CompilerDesugaringKind}; +use syntax::source_map::{MultiSpan, ExpnKind, DesugaringKind}; use syntax::early_buffered_lints::BufferedEarlyLintId; use syntax::edition::Edition; use syntax::symbol::{Symbol, sym}; @@ -883,11 +883,11 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { None => return false, }; - match info.format { - ExpnFormat::MacroAttribute(..) => true, // definitely a plugin - ExpnFormat::CompilerDesugaring(CompilerDesugaringKind::ForLoop) => false, - ExpnFormat::CompilerDesugaring(_) => true, // well, it's "external" - ExpnFormat::MacroBang(..) => { + match info.kind { + ExpnKind::MacroAttribute(..) => true, // definitely a plugin + ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, + ExpnKind::Desugaring(_) => true, // well, it's "external" + ExpnKind::MacroBang(..) => { let def_site = match info.def_site { Some(span) => span, // no span for the def_site means it's an external macro @@ -911,8 +911,8 @@ pub fn in_derive_expansion(span: Span) -> bool { None => return false, }; - match info.format { - ExpnFormat::MacroAttribute(symbol) => symbol.as_str().starts_with("derive("), + match info.kind { + ExpnKind::MacroAttribute(symbol) => symbol.as_str().starts_with("derive("), _ => false, } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 59a032d53cfd6..ff868bf2a2ad2 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -928,7 +928,7 @@ impl<'tcx> LocalDecl<'tcx> { /// `__next` from a `for` loop. #[inline] pub fn from_compiler_desugaring(&self) -> bool { - self.source_info.span.compiler_desugaring_kind().is_some() + self.source_info.span.desugaring_kind().is_some() } /// Creates a new `LocalDecl` for a temporary. diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d6cc68bcdab46..fb7ed14744502 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,7 +36,7 @@ use errors::{Applicability, DiagnosticBuilder}; use std::fmt; use syntax::ast; use syntax::symbol::sym; -use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnFormat}; +use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnKind}; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_fulfillment_errors(&self, @@ -62,7 +62,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // if one is the result of a desugaring and the other is not. let mut span = error.obligation.cause.span; if let Some(ExpnInfo { - format: ExpnFormat::CompilerDesugaring(_), + kind: ExpnKind::Desugaring(_), def_site: Some(def_span), .. }) = span.ctxt().outer_expn_info() { @@ -373,9 +373,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { flags.push((sym::parent_trait, Some(t))); } - if let Some(k) = obligation.cause.span.compiler_desugaring_kind() { + if let Some(k) = obligation.cause.span.desugaring_kind() { flags.push((sym::from_desugaring, None)); - flags.push((sym::from_desugaring, Some(k.name().to_string()))); + flags.push((sym::from_desugaring, Some(k.descr().to_string()))); } let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index d402b0ddf6e85..18bbb2571288d 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -8,7 +8,7 @@ use syntax::{ }, attr, source_map::{ - respan, ExpnInfo, MacroAttribute, + respan, ExpnInfo, ExpnKind, }, ext::{ base::{ExtCtxt, Resolver}, @@ -87,7 +87,8 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { // Create a fresh Mark for the new macro expansion we are about to do let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::global_allocator), item.span, self.sess.edition, &[sym::rustc_attrs] + ExpnKind::MacroAttribute(sym::global_allocator), item.span, self.sess.edition, + &[sym::rustc_attrs], )); // Tie the span to the macro expansion info we just created diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 34db080ef6633..9a581cb03ecd0 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -33,7 +33,7 @@ use std::cell::{Cell, RefCell}; use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; -use syntax::source_map::CompilerDesugaringKind; +use syntax::source_map::DesugaringKind; use syntax_pos::{MultiSpan, Span}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; @@ -734,8 +734,8 @@ impl BorrowckCtxt<'_, 'tcx> { }, moved_lp.ty)); } - if let (Some(CompilerDesugaringKind::ForLoop), Ok(snippet)) = ( - move_span.compiler_desugaring_kind(), + if let (Some(DesugaringKind::ForLoop), Ok(snippet)) = ( + move_span.desugaring_kind(), self.tcx.sess.source_map().span_to_snippet(move_span), ) { if !snippet.starts_with("&") { diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index f23cffeda689c..7b5fce4abbc4b 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; use rustc_errors::{Applicability, DiagnosticBuilder}; use syntax_pos::Span; -use syntax::source_map::CompilerDesugaringKind; +use syntax::source_map::DesugaringKind; use super::nll::explain_borrow::BorrowExplanation; use super::nll::region_infer::{RegionName, RegionNameSource}; @@ -174,7 +174,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("variable moved due to use{}", move_spans.describe()), ); } - if Some(CompilerDesugaringKind::ForLoop) == move_span.compiler_desugaring_kind() { + if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() { if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { err.span_suggestion( move_span, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 25ac93cc2422c..31a9766af303a 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/src/librustc_mir/borrow_check/mod.rs @@ -335,7 +335,7 @@ fn do_mir_borrowck<'a, 'tcx>( } let span = local_decl.source_info.span; - if span.compiler_desugaring_kind().is_some() { + if span.desugaring_kind().is_some() { // If the `mut` arises as part of a desugaring, we should ignore it. continue; } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index effd69dc61ddc..fab2537f9d8f1 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -37,7 +37,6 @@ use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::print::pprust; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{arg_to_string, ty_to_string}; -use syntax::source_map::MacroAttribute; use syntax_pos::*; use json_dumper::JsonDumper; @@ -845,7 +844,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let callee_span = callee.def_site?; // Ignore attribute macros, their spans are usually mangled - if let MacroAttribute(_) = callee.format { + if let ExpnKind::MacroAttribute(_) = callee.kind { return None; } @@ -870,7 +869,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let callee_span = self.span_from_span(callee_span); Some(MacroRef { span: callsite_span, - qualname: callee.format.name().to_string(), // FIXME: generate the real qualname + qualname: callee.kind.descr().to_string(), // FIXME: generate the real qualname callee_span, }) } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index d24f92a6fafef..de42a6a35c89a 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -15,7 +15,7 @@ use syntax::ast; use syntax::source_map::Spanned; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; -use syntax_pos::hygiene::CompilerDesugaringKind; +use syntax_pos::hygiene::DesugaringKind; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::cmp; @@ -184,7 +184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // In the case of `if`- and `while`-expressions we've already checked // that `scrutinee: bool`. We know that the pattern is `true`, // so an error here would be a duplicate and from the wrong POV. - s.is_compiler_desugaring(CompilerDesugaringKind::CondTemporary) + s.is_desugaring(DesugaringKind::CondTemporary) }) .is_some()); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4acba6d38fa25..d32ee67f74588 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -119,7 +119,7 @@ use rustc::ty::subst::{UnpackedKind, Subst, InternalSubsts, SubstsRef, UserSelfT use rustc::ty::util::{Representability, IntTypeExt, Discr}; use rustc::ty::layout::VariantIdx; use syntax_pos::{self, BytePos, Span, MultiSpan}; -use syntax_pos::hygiene::CompilerDesugaringKind; +use syntax_pos::hygiene::DesugaringKind; use syntax::ast; use syntax::attr; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -2165,7 +2165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If span arose from a desugaring of `if` or `while`, then it is the condition itself, // which diverges, that we are about to lint on. This gives suboptimal diagnostics. // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. - !span.is_compiler_desugaring(CompilerDesugaringKind::CondTemporary) { + !span.is_desugaring(DesugaringKind::CondTemporary) { self.diverges.set(Diverges::WarnedAlways); debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 09ff44115b49d..0c986574cece4 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -15,7 +15,7 @@ use crate::tokenstream::{self, TokenStream}; use errors::{DiagnosticBuilder, DiagnosticId}; use smallvec::{smallvec, SmallVec}; use syntax_pos::{Span, MultiSpan, DUMMY_SP}; -use syntax_pos::hygiene::{ExpnInfo, ExpnFormat}; +use syntax_pos::hygiene::{ExpnInfo, ExpnKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; @@ -642,18 +642,18 @@ impl SyntaxExtension { } } - fn expn_format(&self, symbol: Symbol) -> ExpnFormat { + fn expn_kind(&self, descr: Symbol) -> ExpnKind { match self.kind { SyntaxExtensionKind::Bang(..) | - SyntaxExtensionKind::LegacyBang(..) => ExpnFormat::MacroBang(symbol), - _ => ExpnFormat::MacroAttribute(symbol), + SyntaxExtensionKind::LegacyBang(..) => ExpnKind::MacroBang(descr), + _ => ExpnKind::MacroAttribute(descr), } } - pub fn expn_info(&self, call_site: Span, format: &str) -> ExpnInfo { + pub fn expn_info(&self, call_site: Span, descr: &str) -> ExpnInfo { ExpnInfo { call_site, - format: self.expn_format(Symbol::intern(format)), + kind: self.expn_kind(Symbol::intern(descr)), def_site: Some(self.span), default_transparency: self.default_transparency, allow_internal_unstable: self.allow_internal_unstable.clone(), @@ -780,7 +780,7 @@ impl<'a> ExtCtxt<'a> { let mut last_macro = None; loop { if ctxt.outer_expn_info().map_or(None, |info| { - if info.format.name() == sym::include { + if info.kind.descr() == sym::include { // Stop going up the backtrace once include! is encountered return None; } diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 2a56f3dd7566b..24050be792b94 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -1,6 +1,6 @@ use crate::attr::HasAttrs; use crate::ast; -use crate::source_map::{ExpnInfo, ExpnFormat}; +use crate::source_map::{ExpnInfo, ExpnKind}; use crate::ext::base::ExtCtxt; use crate::ext::build::AstBuilder; use crate::parse::parser::PathStyle; @@ -57,7 +57,7 @@ pub fn add_derived_markers(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P pretty_name.push(')'); cx.current_expansion.mark.set_expn_info(ExpnInfo::with_unstable( - ExpnFormat::MacroAttribute(Symbol::intern(&pretty_name)), span, cx.parse_sess.edition, + ExpnKind::MacroAttribute(Symbol::intern(&pretty_name)), span, cx.parse_sess.edition, &[sym::rustc_attrs, sym::structural_match], )); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 053686b8b1f27..879069c1418e4 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -506,7 +506,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let suggested_limit = self.cx.ecfg.recursion_limit * 2; let mut err = self.cx.struct_span_err(info.call_site, &format!("recursion limit reached while expanding the macro `{}`", - info.format.name())); + info.kind.descr())); err.help(&format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", suggested_limit)); diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index ac30cbb471aea..bbf62ef1e2361 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -7,10 +7,8 @@ //! within the SourceMap, which upon request can be converted to line and column //! information, source code snippets, etc. - pub use syntax_pos::*; -pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo}; -pub use ExpnFormat::*; +pub use syntax_pos::hygiene::{ExpnKind, ExpnInfo}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 6630bf9081546..7ee073117e96f 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -3,7 +3,7 @@ use crate::attr; use crate::edition::Edition; use crate::ext::hygiene::{Mark, SyntaxContext}; use crate::symbol::{Ident, Symbol, kw, sym}; -use crate::source_map::{ExpnInfo, MacroAttribute, dummy_spanned, respan}; +use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan}; use crate::ptr::P; use crate::tokenstream::TokenStream; @@ -17,7 +17,7 @@ use syntax_pos::{DUMMY_SP, Span}; fn ignored_span(sp: Span, edition: Edition) -> Span { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(Symbol::intern("std_inject")), sp, edition, &[sym::prelude_import] + ExpnKind::MacroAttribute(Symbol::intern("std_inject")), sp, edition, &[sym::prelude_import] )); sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index c717f140ca368..35a1a552a13fb 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -15,7 +15,7 @@ use smallvec::{smallvec, SmallVec}; use syntax_pos::{DUMMY_SP, NO_EXPANSION, Span, SourceFile, BytePos}; use crate::attr::{self, HasAttrs}; -use crate::source_map::{self, SourceMap, ExpnInfo, MacroAttribute, dummy_spanned, respan}; +use crate::source_map::{self, SourceMap, ExpnInfo, ExpnKind, dummy_spanned, respan}; use crate::config; use crate::entry::{self, EntryPointType}; use crate::ext::base::{ExtCtxt, Resolver}; @@ -280,7 +280,7 @@ fn generate_test_harness(sess: &ParseSess, }; mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::test_case), DUMMY_SP, sess.edition, + ExpnKind::MacroAttribute(sym::test_case), DUMMY_SP, sess.edition, &[sym::main, sym::test, sym::rustc_attrs], )); diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs index 45e65288a24ee..dee8f4b3eb532 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -4,7 +4,7 @@ use crate::deriving; use syntax::ast::{self, Ident}; use syntax::attr; -use syntax::source_map::{ExpnInfo, MacroAttribute, respan}; +use syntax::source_map::{ExpnInfo, ExpnKind, respan}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; @@ -348,7 +348,7 @@ fn mk_decls( ) -> P { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, + ExpnKind::MacroAttribute(sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, &[sym::rustc_attrs, Symbol::intern("proc_macro_internals")], )); let span = DUMMY_SP.apply_mark(mark); diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 24d3055e71140..7f4f1fd7e0196 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -9,7 +9,7 @@ use syntax::ast; use syntax::print::pprust; use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; -use syntax::source_map::{ExpnInfo, MacroAttribute}; +use syntax::source_map::{ExpnInfo, ExpnKind}; use std::iter; pub fn expand_test( @@ -63,7 +63,7 @@ pub fn expand_test_or_bench( let (sp, attr_sp) = { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::test), attr_sp, cx.parse_sess.edition, + ExpnKind::MacroAttribute(sym::test), attr_sp, cx.parse_sess.edition, &[sym::rustc_attrs, sym::test], )); (item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)), diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs index 186673c142f14..5f88e2e098a23 100644 --- a/src/libsyntax_ext/test_case.rs +++ b/src/libsyntax_ext/test_case.rs @@ -16,7 +16,7 @@ use syntax::ast; use syntax::source_map::respan; use syntax::symbol::sym; use syntax_pos::Span; -use syntax::source_map::{ExpnInfo, MacroAttribute}; +use syntax::source_map::{ExpnInfo, ExpnKind}; pub fn expand( ecx: &mut ExtCtxt<'_>, @@ -29,7 +29,7 @@ pub fn expand( let sp = { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::test_case), attr_sp, ecx.parse_sess.edition, + ExpnKind::MacroAttribute(sym::test_case), attr_sp, ecx.parse_sess.edition, &[sym::test, sym::rustc_attrs], )); attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 6a2aba17a793e..f36a4d5816e5b 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -162,7 +162,7 @@ impl Mark { HygieneData::with(|data| { if data.default_transparency(self) == Transparency::Opaque { if let Some(expn_info) = &data.marks[self.0 as usize].expn_info { - if let ExpnFormat::MacroAttribute(name) = expn_info.format { + if let ExpnKind::MacroAttribute(name) = expn_info.kind { if name.as_str().starts_with("derive(") { return true; } @@ -654,7 +654,7 @@ pub struct ExpnInfo { /// pointing to the `foo!` invocation. pub call_site: Span, /// The format with which the macro was invoked. - pub format: ExpnFormat, + pub kind: ExpnKind, // --- The part specific to the macro/desugaring definition. // --- FIXME: Share it between expansions with the same definition. @@ -681,10 +681,10 @@ pub struct ExpnInfo { impl ExpnInfo { /// Constructs an expansion info with default properties. - pub fn default(format: ExpnFormat, call_site: Span, edition: Edition) -> ExpnInfo { + pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnInfo { ExpnInfo { call_site, - format, + kind, def_site: None, default_transparency: Transparency::SemiTransparent, allow_internal_unstable: None, @@ -694,31 +694,31 @@ impl ExpnInfo { } } - pub fn with_unstable(format: ExpnFormat, call_site: Span, edition: Edition, + pub fn with_unstable(kind: ExpnKind, call_site: Span, edition: Edition, allow_internal_unstable: &[Symbol]) -> ExpnInfo { ExpnInfo { allow_internal_unstable: Some(allow_internal_unstable.into()), - ..ExpnInfo::default(format, call_site, edition) + ..ExpnInfo::default(kind, call_site, edition) } } } /// The source of expansion. #[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] -pub enum ExpnFormat { +pub enum ExpnKind { /// e.g., #[derive(...)] MacroAttribute(Symbol), /// e.g., `format!()` MacroBang(Symbol), /// Desugaring done by the compiler during HIR lowering. - CompilerDesugaring(CompilerDesugaringKind) + Desugaring(DesugaringKind) } -impl ExpnFormat { - pub fn name(&self) -> Symbol { +impl ExpnKind { + pub fn descr(&self) -> Symbol { match *self { - ExpnFormat::MacroBang(name) | ExpnFormat::MacroAttribute(name) => name, - ExpnFormat::CompilerDesugaring(kind) => kind.name(), + ExpnKind::MacroBang(name) | ExpnKind::MacroAttribute(name) => name, + ExpnKind::Desugaring(kind) => kind.descr(), } } } @@ -753,7 +753,7 @@ impl MacroKind { /// The kind of compiler desugaring. #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] -pub enum CompilerDesugaringKind { +pub enum DesugaringKind { /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`. /// However, we do not want to blame `c` for unreachability but rather say that `i` /// is unreachable. This desugaring kind allows us to avoid blaming `c`. @@ -770,16 +770,16 @@ pub enum CompilerDesugaringKind { ForLoop, } -impl CompilerDesugaringKind { - pub fn name(self) -> Symbol { +impl DesugaringKind { + pub fn descr(self) -> Symbol { Symbol::intern(match self { - CompilerDesugaringKind::CondTemporary => "if and while condition", - CompilerDesugaringKind::Async => "async", - CompilerDesugaringKind::Await => "await", - CompilerDesugaringKind::QuestionMark => "?", - CompilerDesugaringKind::TryBlock => "try block", - CompilerDesugaringKind::ExistentialType => "existential type", - CompilerDesugaringKind::ForLoop => "for loop", + DesugaringKind::CondTemporary => "if and while condition", + DesugaringKind::Async => "async", + DesugaringKind::Await => "await", + DesugaringKind::QuestionMark => "?", + DesugaringKind::TryBlock => "try block", + DesugaringKind::ExistentialType => "existential type", + DesugaringKind::ForLoop => "for loop", }) } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 07b9f60932024..d4c1958f7e265 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -27,7 +27,7 @@ extern crate serialize as rustc_serialize; // used by deriving pub mod edition; use edition::Edition; pub mod hygiene; -pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnFormat, CompilerDesugaringKind}; +pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnKind, DesugaringKind}; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -403,10 +403,10 @@ impl Span { } /// Checks if this span arises from a compiler desugaring of kind `kind`. - pub fn is_compiler_desugaring(&self, kind: CompilerDesugaringKind) -> bool { + pub fn is_desugaring(&self, kind: DesugaringKind) -> bool { match self.ctxt().outer_expn_info() { - Some(info) => match info.format { - ExpnFormat::CompilerDesugaring(k) => k == kind, + Some(info) => match info.kind { + ExpnKind::Desugaring(k) => k == kind, _ => false, }, None => false, @@ -415,10 +415,10 @@ impl Span { /// Returns the compiler desugaring that created this span, or `None` /// if this span is not from a desugaring. - pub fn compiler_desugaring_kind(&self) -> Option { + pub fn desugaring_kind(&self) -> Option { match self.ctxt().outer_expn_info() { - Some(info) => match info.format { - ExpnFormat::CompilerDesugaring(k) => Some(k), + Some(info) => match info.kind { + ExpnKind::Desugaring(k) => Some(k), _ => None }, None => None @@ -441,14 +441,14 @@ impl Span { while let Some(info) = self.ctxt().outer_expn_info() { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { - let (pre, post) = match info.format { - ExpnFormat::MacroAttribute(..) => ("#[", "]"), - ExpnFormat::MacroBang(..) => ("", "!"), - ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"), + let (pre, post) = match info.kind { + ExpnKind::MacroAttribute(..) => ("#[", "]"), + ExpnKind::MacroBang(..) => ("", "!"), + ExpnKind::Desugaring(..) => ("desugaring of `", "`"), }; result.push(MacroBacktrace { call_site: info.call_site, - macro_decl_name: format!("{}{}{}", pre, info.format.name(), post), + macro_decl_name: format!("{}{}{}", pre, info.kind.descr(), post), def_site_span: info.def_site, }); } From f1d4ebf01505877ff36ba63f8a26ea8ea0973969 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 20 Jun 2019 02:33:39 +0300 Subject: [PATCH 14/37] Remove unnecessary expansions created by `#[test_case/test/bench]` The expansions were created to allow unstable things inside `#[test_case/test/bench]`, but that's not a proper way to do that. Put the required `allow_internal_unstable`s into the macros' properties instead. --- src/libcore/macros.rs | 3 +++ src/libsyntax_ext/lib.rs | 24 ++++++++++++++++-------- src/libsyntax_ext/test.rs | 14 +++----------- src/libsyntax_ext/test_case.rs | 14 ++------------ 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 2e999a0682b40..293a2dd94922f 100644 --- a/src/libcore/macros.rs +++ b/src/libcore/macros.rs @@ -1244,12 +1244,14 @@ mod builtin { /// Attribute macro applied to a function to turn it into a unit test. #[stable(feature = "rust1", since = "1.0.0")] + #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] pub macro test($item:item) { /* compiler built-in */ } /// Attribute macro applied to a function to turn it into a benchmark test. #[stable(feature = "rust1", since = "1.0.0")] + #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] pub macro bench($item:item) { /* compiler built-in */ } @@ -1257,6 +1259,7 @@ mod builtin { /// An implementation detail of the `#[test]` and `#[bench]` macros. #[unstable(feature = "custom_test_frameworks", issue = "50297", reason = "custom test frameworks are an unstable feature")] + #[allow_internal_unstable(test, rustc_attrs)] #[rustc_builtin_macro] #[rustc_macro_transparency = "semitransparent"] pub macro test_case($item:item) { /* compiler built-in */ } diff --git a/src/libsyntax_ext/lib.rs b/src/libsyntax_ext/lib.rs index 62530f4fe7b33..da0f8ca6da090 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -72,6 +72,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, let mut register = |name, ext| { resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Lrc::new(ext)); }; + macro_rules! register { ($( $name:ident: $f:expr, )*) => { $( register(sym::$name, SyntaxExtension::default( @@ -125,24 +126,31 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, trace_macros: trace_macros::expand_trace_macros, } + let allow_internal_unstable = Some([sym::test, sym::rustc_attrs][..].into()); register(sym::test_case, SyntaxExtension { stability: Some(Stability::unstable( sym::custom_test_frameworks, Some(Symbol::intern(EXPLAIN_CUSTOM_TEST_FRAMEWORKS)), 50297, )), + allow_internal_unstable: allow_internal_unstable.clone(), ..SyntaxExtension::default( SyntaxExtensionKind::LegacyAttr(Box::new(test_case::expand)), edition ) }); - register(sym::test, SyntaxExtension::default( - SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_test)), edition - )); - register(sym::bench, SyntaxExtension::default( - SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_bench)), edition - )); - - // format_args uses `unstable` things internally. + register(sym::test, SyntaxExtension { + allow_internal_unstable: allow_internal_unstable.clone(), + ..SyntaxExtension::default( + SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_test)), edition + ) + }); + register(sym::bench, SyntaxExtension { + allow_internal_unstable, + ..SyntaxExtension::default( + SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_bench)), edition + ) + }); + let allow_internal_unstable = Some([sym::fmt_internals][..].into()); register(sym::format_args, SyntaxExtension { allow_internal_unstable: allow_internal_unstable.clone(), diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 7f4f1fd7e0196..c5c5ef57b3122 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -3,13 +3,12 @@ use syntax::ext::base::*; use syntax::ext::build::AstBuilder; -use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::ext::hygiene::SyntaxContext; use syntax::attr; use syntax::ast; use syntax::print::pprust; use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; -use syntax::source_map::{ExpnInfo, ExpnKind}; use std::iter; pub fn expand_test( @@ -60,15 +59,8 @@ pub fn expand_test_or_bench( return vec![Annotatable::Item(item)]; } - let (sp, attr_sp) = { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(sym::test), attr_sp, cx.parse_sess.edition, - &[sym::rustc_attrs, sym::test], - )); - (item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)), - attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark))) - }; + let ctxt = SyntaxContext::empty().apply_mark(cx.current_expansion.mark); + let (sp, attr_sp) = (item.span.with_ctxt(ctxt), attr_sp.with_ctxt(ctxt)); // Gensym "test" so we can extern crate without conflicting with any local names let test_id = cx.ident_of("test").gensym(); diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs index 5f88e2e098a23..af2cf42e04bb9 100644 --- a/src/libsyntax_ext/test_case.rs +++ b/src/libsyntax_ext/test_case.rs @@ -11,12 +11,11 @@ use syntax::ext::base::*; use syntax::ext::build::AstBuilder; -use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::ext::hygiene::SyntaxContext; use syntax::ast; use syntax::source_map::respan; use syntax::symbol::sym; use syntax_pos::Span; -use syntax::source_map::{ExpnInfo, ExpnKind}; pub fn expand( ecx: &mut ExtCtxt<'_>, @@ -26,17 +25,8 @@ pub fn expand( ) -> Vec { if !ecx.ecfg.should_test { return vec![]; } - let sp = { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(sym::test_case), attr_sp, ecx.parse_sess.edition, - &[sym::test, sym::rustc_attrs], - )); - attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) - }; - + let sp = attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(ecx.current_expansion.mark)); let mut item = anno_item.expect_item(); - item = item.map(|mut item| { item.vis = respan(item.vis.span, ast::VisibilityKind::Public); item.ident = item.ident.gensym(); From 62a1f5dbc0bbcf875b21dce643ae8b2ae971c74e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 20 Jun 2019 10:34:51 +0300 Subject: [PATCH 15/37] hygiene: Remove some dead code --- src/libsyntax_pos/hygiene.rs | 28 +--------------------------- 1 file changed, 1 insertion(+), 27 deletions(-) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index f36a4d5816e5b..f8318f54320e3 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -31,7 +31,7 @@ use crate::edition::Edition; use crate::symbol::{kw, Symbol}; use serialize::{Encodable, Decodable, Encoder, Decoder}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use std::fmt; @@ -130,32 +130,6 @@ impl Mark { HygieneData::with(|data| data.is_descendant_of(self, data.outer(ctxt))) } - /// Computes a mark such that both input marks are descendants of (or equal to) the returned - /// mark. That is, the following holds: - /// - /// ```rust - /// let la = least_ancestor(a, b); - /// assert!(a.is_descendant_of(la)) - /// assert!(b.is_descendant_of(la)) - /// ``` - pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark { - HygieneData::with(|data| { - // Compute the path from a to the root - let mut a_path = FxHashSet::::default(); - while a != Mark::root() { - a_path.insert(a); - a = data.marks[a.0 as usize].parent; - } - - // While the path from b to the root hasn't intersected, move up the tree - while !a_path.contains(&b) { - b = data.marks[b.0 as usize].parent; - } - - b - }) - } - // Used for enabling some compatibility fallback in resolve. #[inline] pub fn looks_like_proc_macro_derive(self) -> bool { From a138e9d625bf83c45d3835b12d7689b730dc4e9a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 29 Jun 2019 02:30:53 +0300 Subject: [PATCH 16/37] expand: Get rid of `resolve_macro_path` It was used to choose whether to apply derive markers like `#[rustc_copy_clone_marker]` or not, but it was called before all the data required for resolution is available, so it could work incorrectly in some corner cases (like user-defined derives name `Copy` or `Eq`). Delay the decision about markers until the proper resolution results are available instead. --- src/librustc_resolve/macros.rs | 7 ------- src/libsyntax/ext/base.rs | 3 --- src/libsyntax/ext/expand.rs | 22 +++++++++++----------- 3 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index a3e00bcb81a9f..61300e3ee3cee 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -242,13 +242,6 @@ impl<'a> base::Resolver for Resolver<'a> { Ok(Some(ext)) } - fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark, - derives_in_scope: Vec, force: bool) - -> Result, Determinacy> { - let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - Ok(self.resolve_macro_to_res(path, kind, &parent_scope, false, force)?.1) - } - fn check_unused_macros(&self) { for (&node_id, &span) in self.unused_macros.iter() { self.session.buffer_lint( diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 0c986574cece4..267046655ffdc 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -680,9 +680,6 @@ pub trait Resolver { fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) -> Result>, Determinacy>; - fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark, - derives_in_scope: Vec, force: bool) - -> Result, Determinacy>; fn check_unused_macros(&self); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 879069c1418e4..bb7d7352e055a 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -208,6 +208,7 @@ pub enum InvocationKind { Derive { path: Path, item: Annotatable, + item_with_markers: Annotatable, }, } @@ -362,19 +363,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { derives.reserve(traits.len()); invocations.reserve(traits.len()); - for path in &traits { + for path in traits { let mark = Mark::fresh(self.cx.current_expansion.mark); derives.push(mark); - let item = match self.cx.resolver.resolve_macro_path( - path, MacroKind::Derive, Mark::root(), Vec::new(), false) { - Ok(ext) => match ext.kind { - SyntaxExtensionKind::LegacyDerive(..) => item_with_markers.clone(), - _ => item.clone(), - }, - _ => item.clone(), - }; invocations.push(Invocation { - kind: InvocationKind::Derive { path: path.clone(), item }, + kind: InvocationKind::Derive { + path, + item: item.clone(), + item_with_markers: item_with_markers.clone(), + }, fragment_kind: invoc.fragment_kind, expansion_data: ExpansionData { mark, @@ -737,7 +734,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ext: &SyntaxExtension) -> Option { let (path, item) = match invoc.kind { - InvocationKind::Derive { path, item } => (path, item), + InvocationKind::Derive { path, item, item_with_markers } => match ext.kind { + SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers), + _ => (path, item), + } _ => unreachable!(), }; if !item.derive_allowed() { From 3eafaae510a71a76eedcc2909e7c908bd49d5c46 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 30 Jun 2019 03:05:52 +0300 Subject: [PATCH 17/37] syntax: Make def-site span mandatory in ExpnInfo/MacroBacktrace/DiagnosticSpanMacroExpansion We have to deal with dummy spans anyway Remove def-site span from expander interfaces. It's not used by the expansion infra, only by specific expanders, which can keep it themselves if they want it. --- src/librustc/hir/lowering.rs | 2 +- src/librustc/lint/mod.rs | 12 ++-- src/librustc/traits/error_reporting.rs | 9 +-- src/librustc_errors/emitter.rs | 64 +++++++++---------- src/librustc_save_analysis/lib.rs | 5 +- src/libsyntax/ext/base.rs | 4 +- src/libsyntax/ext/expand.rs | 2 +- src/libsyntax/ext/tt/macro_rules.rs | 14 ++-- src/libsyntax/json.rs | 9 ++- src/libsyntax_pos/hygiene.rs | 10 ++- src/libsyntax_pos/lib.rs | 4 +- .../auxiliary/plugin-args.rs | 3 +- 12 files changed, 61 insertions(+), 77 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index 549c34d961aa4..c44fd30be850a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -877,7 +877,7 @@ impl<'a> LoweringContext<'a> { ) -> Span { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo { - def_site: Some(span), + def_site: span, allow_internal_unstable, ..ExpnInfo::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) }); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 2bf4f1d3cfbba..9876d6c1fa59b 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -888,13 +888,11 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::MacroBang(..) => { - let def_site = match info.def_site { - Some(span) => span, - // no span for the def_site means it's an external macro - None => return true, - }; - - match sess.source_map().span_to_snippet(def_site) { + if info.def_site.is_dummy() { + // dummy span for the def_site means it's an external macro + return true; + } + match sess.source_map().span_to_snippet(info.def_site) { Ok(code) => !code.starts_with("macro_rules"), // no snippet = external macro or compiler-builtin expansion Err(_) => true, diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index fb7ed14744502..a7dfbd688c14e 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -61,12 +61,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // We want to ignore desugarings here: spans are equivalent even // if one is the result of a desugaring and the other is not. let mut span = error.obligation.cause.span; - if let Some(ExpnInfo { - kind: ExpnKind::Desugaring(_), - def_site: Some(def_span), - .. - }) = span.ctxt().outer_expn_info() { - span = def_span; + if let Some(ExpnInfo { kind: ExpnKind::Desugaring(_), def_site, .. }) + = span.ctxt().outer_expn_info() { + span = def_site; } error_map.entry(span).or_default().push( diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 83a0fb486fd9a..361b5cd935712 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -723,39 +723,37 @@ impl EmitterWriter { for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() { // Only show macro locations that are local // and display them like a span_note - if let Some(def_site) = trace.def_site_span { - if def_site.is_dummy() { - continue; - } - if always_backtrace { - new_labels.push((def_site, - format!("in this expansion of `{}`{}", - trace.macro_decl_name, - if backtrace_len > 2 { - // if backtrace_len == 1 it'll be pointed - // at by "in this macro invocation" - format!(" (#{})", i + 1) - } else { - String::new() - }))); - } - // Check to make sure we're not in any <*macros> - if !sm.span_to_filename(def_site).is_macros() && - !trace.macro_decl_name.starts_with("desugaring of ") && - !trace.macro_decl_name.starts_with("#[") || - always_backtrace { - new_labels.push((trace.call_site, - format!("in this macro invocation{}", - if backtrace_len > 2 && always_backtrace { - // only specify order when the macro - // backtrace is multiple levels deep - format!(" (#{})", i + 1) - } else { - String::new() - }))); - if !always_backtrace { - break; - } + if trace.def_site_span.is_dummy() { + continue; + } + if always_backtrace { + new_labels.push((trace.def_site_span, + format!("in this expansion of `{}`{}", + trace.macro_decl_name, + if backtrace_len > 2 { + // if backtrace_len == 1 it'll be pointed + // at by "in this macro invocation" + format!(" (#{})", i + 1) + } else { + String::new() + }))); + } + // Check to make sure we're not in any <*macros> + if !sm.span_to_filename(trace.def_site_span).is_macros() && + !trace.macro_decl_name.starts_with("desugaring of ") && + !trace.macro_decl_name.starts_with("#[") || + always_backtrace { + new_labels.push((trace.call_site, + format!("in this macro invocation{}", + if backtrace_len > 2 && always_backtrace { + // only specify order when the macro + // backtrace is multiple levels deep + format!(" (#{})", i + 1) + } else { + String::new() + }))); + if !always_backtrace { + break; } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index fab2537f9d8f1..aeaee1887b95b 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -841,7 +841,6 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let callsite = span.source_callsite(); let callsite_span = self.span_from_span(callsite); let callee = span.source_callee()?; - let callee_span = callee.def_site?; // Ignore attribute macros, their spans are usually mangled if let ExpnKind::MacroAttribute(_) = callee.kind { @@ -855,7 +854,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { .sess .imported_macro_spans .borrow() - .get(&callee_span) + .get(&callee.def_site) { let &(ref mac_name, mac_span) = mac; let mac_span = self.span_from_span(mac_span); @@ -866,7 +865,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { }); } - let callee_span = self.span_from_span(callee_span); + let callee_span = self.span_from_span(callee.def_site); Some(MacroRef { span: callsite_span, qualname: callee.kind.descr().to_string(), // FIXME: generate the real qualname diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 267046655ffdc..2f8d6f00ba792 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -219,7 +219,6 @@ pub trait TTMacroExpander { ecx: &'cx mut ExtCtxt<'_>, span: Span, input: TokenStream, - def_span: Option, ) -> Box; } @@ -236,7 +235,6 @@ impl TTMacroExpander for F ecx: &'cx mut ExtCtxt<'_>, span: Span, input: TokenStream, - _def_span: Option, ) -> Box { struct AvoidInterpolatedIdents; @@ -654,7 +652,7 @@ impl SyntaxExtension { ExpnInfo { call_site, kind: self.expn_kind(Symbol::intern(descr)), - def_site: Some(self.span), + def_site: self.span, default_transparency: self.default_transparency, allow_internal_unstable: self.allow_internal_unstable.clone(), allow_internal_unsafe: self.allow_internal_unsafe, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index bb7d7352e055a..06ff2bc655cf5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -673,7 +673,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { result } SyntaxExtensionKind::LegacyBang(expander) => { - let tok_result = expander.expand(self.cx, span, mac.node.stream(), Some(ext.span)); + let tok_result = expander.expand(self.cx, span, mac.node.stream()); kind.make_from(tok_result) } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 665c794422d49..5c6438a7ef534 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -88,6 +88,7 @@ impl<'a> ParserAnyMacro<'a> { struct MacroRulesMacroExpander { name: ast::Ident, + span: Span, lhses: Vec, rhses: Vec, valid: bool, @@ -99,12 +100,11 @@ impl TTMacroExpander for MacroRulesMacroExpander { cx: &'cx mut ExtCtxt<'_>, sp: Span, input: TokenStream, - def_span: Option, ) -> Box { if !self.valid { return DummyResult::any(sp); } - generic_extension(cx, sp, def_span, self.name, input, &self.lhses, &self.rhses) + generic_extension(cx, sp, self.span, self.name, input, &self.lhses, &self.rhses) } } @@ -117,7 +117,7 @@ fn trace_macros_note(cx: &mut ExtCtxt<'_>, sp: Span, message: String) { fn generic_extension<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, - def_span: Option, + def_span: Span, name: ast::Ident, arg: TokenStream, lhses: &[quoted::TokenTree], @@ -199,10 +199,8 @@ fn generic_extension<'cx>( let span = token.span.substitute_dummy(sp); let mut err = cx.struct_span_err(span, &parse_failure_msg(&token)); err.span_label(span, label); - if let Some(sp) = def_span { - if cx.source_map().span_to_filename(sp).is_real() && !sp.is_dummy() { - err.span_label(cx.source_map().def_span(sp), "when calling this macro"); - } + if !def_span.is_dummy() && cx.source_map().span_to_filename(def_span).is_real() { + err.span_label(cx.source_map().def_span(def_span), "when calling this macro"); } // Check whether there's a missing comma in this macro call, like `println!("{}" a);` @@ -377,7 +375,7 @@ pub fn compile( } let expander: Box<_> = - Box::new(MacroRulesMacroExpander { name: def.ident, lhses, rhses, valid }); + Box::new(MacroRulesMacroExpander { name: def.ident, span: def.span, lhses, rhses, valid }); let (default_transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 767ab74355e66..ec0222d90eb7a 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -170,7 +170,7 @@ struct DiagnosticSpanMacroExpansion { macro_decl_name: String, /// span where macro was defined (if known) - def_site_span: Option, + def_site_span: DiagnosticSpan, } #[derive(RustcEncodable)] @@ -300,14 +300,13 @@ impl DiagnosticSpan { None, backtrace, je); - let def_site_span = bt.def_site_span.map(|sp| { - Self::from_span_full(sp, + let def_site_span = + Self::from_span_full(bt.def_site_span, false, None, None, vec![].into_iter(), - je) - }); + je); Box::new(DiagnosticSpanMacroExpansion { span: call_site, macro_decl_name: bt.macro_decl_name, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index f8318f54320e3..63b692ccdcb93 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -26,7 +26,7 @@ // trigger runtime aborts. (Fortunately these are obvious and easy to fix.) use crate::GLOBALS; -use crate::Span; +use crate::{Span, DUMMY_SP}; use crate::edition::Edition; use crate::symbol::{kw, Symbol}; @@ -632,11 +632,9 @@ pub struct ExpnInfo { // --- The part specific to the macro/desugaring definition. // --- FIXME: Share it between expansions with the same definition. - /// 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. + /// The span of the macro definition (possibly dummy). /// This span serves only informational purpose and is not used for resolution. - pub def_site: Option, + pub def_site: Span, /// Transparency used by `apply_mark` for mark with this expansion info by default. pub default_transparency: Transparency, /// List of #[unstable]/feature-gated features that the macro is allowed to use @@ -659,7 +657,7 @@ impl ExpnInfo { ExpnInfo { call_site, kind, - def_site: None, + def_site: DUMMY_SP, default_transparency: Transparency::SemiTransparent, allow_internal_unstable: None, allow_internal_unsafe: false, diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d4c1958f7e265..1369fca3b4a5e 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -1363,8 +1363,8 @@ pub struct MacroBacktrace { /// name of macro that was applied (e.g., "foo!" or "#[derive(Eq)]") pub macro_decl_name: String, - /// span where macro was defined (if known) - pub def_site_span: Option, + /// span where macro was defined (possibly dummy) + pub def_site_span: Span, } // _____________________________________________________________________________ diff --git a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs index 7cbfef52b4aad..36cee82893a06 100644 --- a/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs +++ b/src/test/run-pass-fulldeps/auxiliary/plugin-args.rs @@ -28,8 +28,7 @@ impl TTMacroExpander for Expander { fn expand<'cx>(&self, ecx: &'cx mut ExtCtxt, sp: Span, - _: TokenStream, - _: Option) -> Box { + _: TokenStream) -> Box { let args = self.args.iter().map(|i| pprust::meta_list_item_to_string(i)) .collect::>().join(", "); MacEager::expr(ecx.expr_str(sp, Symbol::intern(&args))) From 4dcf9b15c451e2994ee92cba6efdd2779a931b99 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 30 Jun 2019 14:57:34 +0300 Subject: [PATCH 18/37] hygiene: Remove some unused impls --- src/libsyntax_pos/hygiene.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 63b692ccdcb93..67dcdabe70168 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -36,10 +36,10 @@ use rustc_data_structures::sync::Lrc; use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). -#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SyntaxContext(u32); -#[derive(Copy, Clone, Debug)] +#[derive(Debug)] struct SyntaxContextData { outer_mark: Mark, transparency: Transparency, @@ -53,10 +53,10 @@ struct SyntaxContextData { } /// A mark is a unique ID associated with a macro expansion. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct Mark(u32); -#[derive(Clone, Debug)] +#[derive(Debug)] struct MarkData { parent: Mark, expn_info: Option, @@ -614,7 +614,7 @@ impl fmt::Debug for SyntaxContext { } /// Extra information for tracking spans of macro and syntax sugar expansion -#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct ExpnInfo { // --- The part unique to each expansion. /// The location of the actual macro invocation or syntax sugar , e.g. @@ -676,7 +676,7 @@ impl ExpnInfo { } /// The source of expansion. -#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum ExpnKind { /// e.g., #[derive(...)] MacroAttribute(Symbol), @@ -724,7 +724,7 @@ impl MacroKind { } /// The kind of compiler desugaring. -#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum DesugaringKind { /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`. /// However, we do not want to blame `c` for unreachability but rather say that `i` From aff9738462e8959c0a3eef57124b08d5f811cdec Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 30 Jun 2019 15:58:56 +0300 Subject: [PATCH 19/37] hygiene: Reuse `MacroKind` in `ExpnKind` Orthogonality and reuse are good. --- src/librustc/ich/impls_syntax.rs | 3 +-- src/librustc/lint/mod.rs | 19 ++++++-------- src/librustc_allocator/expand.rs | 4 +-- src/librustc_resolve/macros.rs | 38 +++++++++++++-------------- src/librustc_save_analysis/lib.rs | 3 ++- src/libsyntax/ext/base.rs | 12 ++------- src/libsyntax/ext/derive.rs | 9 +++---- src/libsyntax/std_inject.rs | 5 ++-- src/libsyntax/test.rs | 4 +-- src/libsyntax_ext/proc_macro_decls.rs | 4 +-- src/libsyntax_pos/hygiene.rs | 34 +++++++++++------------- src/libsyntax_pos/lib.rs | 9 ++++--- 12 files changed, 67 insertions(+), 77 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index f679a65c642f9..69e8c35501961 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -408,8 +408,7 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind { - MacroAttribute(sym), - MacroBang(sym), + Macro(kind, descr), Desugaring(kind) }); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 9876d6c1fa59b..3c8b0041a9847 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -38,6 +38,7 @@ use syntax::ast; use syntax::source_map::{MultiSpan, ExpnKind, DesugaringKind}; use syntax::early_buffered_lints::BufferedEarlyLintId; use syntax::edition::Edition; +use syntax::ext::base::MacroKind; use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; @@ -884,10 +885,9 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { }; match info.kind { - ExpnKind::MacroAttribute(..) => true, // definitely a plugin ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, ExpnKind::Desugaring(_) => true, // well, it's "external" - ExpnKind::MacroBang(..) => { + ExpnKind::Macro(MacroKind::Bang, _) => { if info.def_site.is_dummy() { // dummy span for the def_site means it's an external macro return true; @@ -898,19 +898,16 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { Err(_) => true, } } + ExpnKind::Macro(..) => true, // definitely a plugin } } /// Returns whether `span` originates in a derive macro's expansion pub fn in_derive_expansion(span: Span) -> bool { - let info = match span.ctxt().outer_expn_info() { - Some(info) => info, - // no ExpnInfo means this span doesn't come from a macro - None => return false, - }; - - match info.kind { - ExpnKind::MacroAttribute(symbol) => symbol.as_str().starts_with("derive("), - _ => false, + if let Some(info) = span.ctxt().outer_expn_info() { + if let ExpnKind::Macro(MacroKind::Derive, _) = info.kind { + return true; + } } + false } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 18bbb2571288d..d0eefbb11799f 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -11,7 +11,7 @@ use syntax::{ respan, ExpnInfo, ExpnKind, }, ext::{ - base::{ExtCtxt, Resolver}, + base::{ExtCtxt, MacroKind, Resolver}, build::AstBuilder, expand::ExpansionConfig, hygiene::{Mark, SyntaxContext}, @@ -87,7 +87,7 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { // Create a fresh Mark for the new macro expansion we are about to do let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(sym::global_allocator), item.span, self.sess.edition, + ExpnKind::Macro(MacroKind::Attr, sym::global_allocator), item.span, self.sess.edition, &[sym::rustc_attrs], )); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 61300e3ee3cee..7f57b0a5052af 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -114,17 +114,21 @@ fn sub_namespace_match(candidate: Option, requirement: Option String { - let mut path_str = String::with_capacity(64); - for (i, segment) in path.segments.iter().enumerate() { - if i != 0 { - path_str.push_str("::"); - } - if segment.ident.name != kw::PathRoot { - path_str.push_str(&segment.ident.as_str()) +fn fast_print_path(path: &ast::Path) -> Symbol { + if path.segments.len() == 1 { + return path.segments[0].ident.name + } else { + let mut path_str = String::with_capacity(64); + for (i, segment) in path.segments.iter().enumerate() { + if i != 0 { + path_str.push_str("::"); + } + if segment.ident.name != kw::PathRoot { + path_str.push_str(&segment.ident.as_str()) + } } + Symbol::intern(&path_str) } - path_str } impl<'a> base::Resolver for Resolver<'a> { @@ -219,14 +223,10 @@ impl<'a> base::Resolver for Resolver<'a> { }; let span = invoc.span(); - let path = fast_print_path(path); - let format = match kind { - MacroKind::Derive => format!("derive({})", path), - _ => path.clone(), - }; - invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, &format)); + let descr = fast_print_path(path); + invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, descr)); - self.check_stability_and_deprecation(&ext, &path, span); + self.check_stability_and_deprecation(&ext, descr, span); if let Res::Def(_, def_id) = res { if after_derive { @@ -991,7 +991,7 @@ impl<'a> Resolver<'a> { } } - fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &str, span: Span) { + fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, descr: Symbol, span: Span) { if let Some(stability) = &ext.stability { if let StabilityLevel::Unstable { reason, issue } = stability.level { let feature = stability.feature; @@ -1000,14 +1000,14 @@ impl<'a> Resolver<'a> { } } if let Some(depr) = &stability.rustc_depr { - let (message, lint) = stability::rustc_deprecation_message(depr, path); + let (message, lint) = stability::rustc_deprecation_message(depr, &descr.as_str()); stability::early_report_deprecation( self.session, &message, depr.suggestion, lint, span ); } } if let Some(depr) = &ext.deprecation { - let (message, lint) = stability::deprecation_message(depr, path); + let (message, lint) = stability::deprecation_message(depr, &descr.as_str()); stability::early_report_deprecation(self.session, &message, None, lint, span); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index aeaee1887b95b..2c8f7a44f5a27 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -843,7 +843,8 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let callee = span.source_callee()?; // Ignore attribute macros, their spans are usually mangled - if let ExpnKind::MacroAttribute(_) = callee.kind { + if let ExpnKind::Macro(MacroKind::Attr, _) | + ExpnKind::Macro(MacroKind::Derive, _) = callee.kind { return None; } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2f8d6f00ba792..04f124685cbb5 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -640,18 +640,10 @@ impl SyntaxExtension { } } - fn expn_kind(&self, descr: Symbol) -> ExpnKind { - match self.kind { - SyntaxExtensionKind::Bang(..) | - SyntaxExtensionKind::LegacyBang(..) => ExpnKind::MacroBang(descr), - _ => ExpnKind::MacroAttribute(descr), - } - } - - pub fn expn_info(&self, call_site: Span, descr: &str) -> ExpnInfo { + pub fn expn_info(&self, call_site: Span, descr: Symbol) -> ExpnInfo { ExpnInfo { call_site, - kind: self.expn_kind(Symbol::intern(descr)), + kind: ExpnKind::Macro(self.macro_kind(), descr), def_site: self.span, default_transparency: self.default_transparency, allow_internal_unstable: self.allow_internal_unstable.clone(), diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 24050be792b94..68e7225c3cfc5 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -1,7 +1,7 @@ use crate::attr::HasAttrs; use crate::ast; use crate::source_map::{ExpnInfo, ExpnKind}; -use crate::ext::base::ExtCtxt; +use crate::ext::base::{ExtCtxt, MacroKind}; use crate::ext::build::AstBuilder; use crate::parse::parser::PathStyle; use crate::symbol::{Symbol, sym}; @@ -46,7 +46,7 @@ pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> pub fn add_derived_markers(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::Path], item: &mut T) where T: HasAttrs, { - let (mut names, mut pretty_name) = (FxHashSet::default(), "derive(".to_owned()); + let (mut names, mut pretty_name) = (FxHashSet::default(), String::new()); for (i, path) in traits.iter().enumerate() { if i > 0 { pretty_name.push_str(", "); @@ -54,11 +54,10 @@ pub fn add_derived_markers(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P pretty_name.push_str(&path.to_string()); names.insert(unwrap_or!(path.segments.get(0), continue).ident.name); } - pretty_name.push(')'); cx.current_expansion.mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(Symbol::intern(&pretty_name)), span, cx.parse_sess.edition, - &[sym::rustc_attrs, sym::structural_match], + ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span, + cx.parse_sess.edition, &[sym::rustc_attrs, sym::structural_match], )); let span = span.with_ctxt(cx.backtrace()); diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 7ee073117e96f..81f9ff9b6613b 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -1,7 +1,7 @@ use crate::ast; use crate::attr; use crate::edition::Edition; -use crate::ext::hygiene::{Mark, SyntaxContext}; +use crate::ext::hygiene::{Mark, SyntaxContext, MacroKind}; use crate::symbol::{Ident, Symbol, kw, sym}; use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan}; use crate::ptr::P; @@ -17,7 +17,8 @@ use syntax_pos::{DUMMY_SP, Span}; fn ignored_span(sp: Span, edition: Edition) -> Span { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(Symbol::intern("std_inject")), sp, edition, &[sym::prelude_import] + ExpnKind::Macro(MacroKind::Attr, Symbol::intern("std_inject")), sp, edition, + &[sym::prelude_import], )); sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 35a1a552a13fb..7ec7bb6ff458f 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -21,7 +21,7 @@ use crate::entry::{self, EntryPointType}; use crate::ext::base::{ExtCtxt, Resolver}; use crate::ext::build::AstBuilder; use crate::ext::expand::ExpansionConfig; -use crate::ext::hygiene::{self, Mark, SyntaxContext}; +use crate::ext::hygiene::{self, Mark, SyntaxContext, MacroKind}; use crate::mut_visit::{*, ExpectOne}; use crate::feature_gate::Features; use crate::util::map_in_place::MapInPlace; @@ -280,7 +280,7 @@ fn generate_test_harness(sess: &ParseSess, }; mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(sym::test_case), DUMMY_SP, sess.edition, + ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, sess.edition, &[sym::main, sym::test, sym::rustc_attrs], )); diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs index dee8f4b3eb532..0733a8ec95c71 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -5,7 +5,7 @@ use crate::deriving; use syntax::ast::{self, Ident}; use syntax::attr; use syntax::source_map::{ExpnInfo, ExpnKind, respan}; -use syntax::ext::base::ExtCtxt; +use syntax::ext::base::{ExtCtxt, MacroKind}; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; use syntax::ext::hygiene::Mark; @@ -348,7 +348,7 @@ fn mk_decls( ) -> P { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, + ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, &[sym::rustc_attrs, Symbol::intern("proc_macro_internals")], )); let span = DUMMY_SP.apply_mark(mark); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 67dcdabe70168..28d452233cceb 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -135,11 +135,9 @@ impl Mark { pub fn looks_like_proc_macro_derive(self) -> bool { HygieneData::with(|data| { if data.default_transparency(self) == Transparency::Opaque { - if let Some(expn_info) = &data.marks[self.0 as usize].expn_info { - if let ExpnKind::MacroAttribute(name) = expn_info.kind { - if name.as_str().starts_with("derive(") { - return true; - } + if let Some(expn_info) = data.expn_info(self) { + if let ExpnKind::Macro(MacroKind::Derive, _) = expn_info.kind { + return true; } } } @@ -193,7 +191,7 @@ impl HygieneData { } fn default_transparency(&self, mark: Mark) -> Transparency { - self.marks[mark.0 as usize].expn_info.as_ref().map_or( + self.expn_info(mark).map_or( Transparency::SemiTransparent, |einfo| einfo.default_transparency ) } @@ -613,7 +611,8 @@ impl fmt::Debug for SyntaxContext { } } -/// Extra information for tracking spans of macro and syntax sugar expansion +/// A subset of properties from both macro definition and macro call available through global data. +/// Avoid using this if you have access to the original definition or call structures. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct ExpnInfo { // --- The part unique to each expansion. @@ -627,7 +626,7 @@ pub struct ExpnInfo { /// call_site span would have its own ExpnInfo, with the call_site /// pointing to the `foo!` invocation. pub call_site: Span, - /// The format with which the macro was invoked. + /// The kind of this expansion - macro or compiler desugaring. pub kind: ExpnKind, // --- The part specific to the macro/desugaring definition. @@ -675,13 +674,12 @@ impl ExpnInfo { } } -/// The source of expansion. +/// Expansion kind. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum ExpnKind { - /// e.g., #[derive(...)] - MacroAttribute(Symbol), - /// e.g., `format!()` - MacroBang(Symbol), + /// Expansion produced by a macro. + /// FIXME: Some code injected by the compiler before HIR lowering also gets this kind. + Macro(MacroKind, Symbol), /// Desugaring done by the compiler during HIR lowering. Desugaring(DesugaringKind) } @@ -689,8 +687,8 @@ pub enum ExpnKind { impl ExpnKind { pub fn descr(&self) -> Symbol { match *self { - ExpnKind::MacroBang(name) | ExpnKind::MacroAttribute(name) => name, - ExpnKind::Desugaring(kind) => kind.descr(), + ExpnKind::Macro(_, descr) => descr, + ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()), } } } @@ -743,8 +741,8 @@ pub enum DesugaringKind { } impl DesugaringKind { - pub fn descr(self) -> Symbol { - Symbol::intern(match self { + pub fn descr(self) -> &'static str { + match self { DesugaringKind::CondTemporary => "if and while condition", DesugaringKind::Async => "async", DesugaringKind::Await => "await", @@ -752,7 +750,7 @@ impl DesugaringKind { DesugaringKind::TryBlock => "try block", DesugaringKind::ExistentialType => "existential type", DesugaringKind::ForLoop => "for loop", - }) + } } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 1369fca3b4a5e..4fd27ce4f9633 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -27,7 +27,7 @@ extern crate serialize as rustc_serialize; // used by deriving pub mod edition; use edition::Edition; pub mod hygiene; -pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnKind, DesugaringKind}; +pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnKind, MacroKind, DesugaringKind}; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -442,9 +442,12 @@ impl Span { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { let (pre, post) = match info.kind { - ExpnKind::MacroAttribute(..) => ("#[", "]"), - ExpnKind::MacroBang(..) => ("", "!"), ExpnKind::Desugaring(..) => ("desugaring of `", "`"), + ExpnKind::Macro(macro_kind, _) => match macro_kind { + MacroKind::Bang => ("", "!"), + MacroKind::Attr => ("#[", "]"), + MacroKind::Derive => ("#[derive(", ")]"), + } }; result.push(MacroBacktrace { call_site: info.call_site, From e2729460661c9bafb2e1862ddd0a63f75ae553e7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 2 Jul 2019 13:47:28 +0300 Subject: [PATCH 20/37] def_collector: Simplify tracking of macro invocation parents Avoid the tricky scheme with callbacks and keep the invocation parent data where it logically belongs - in `Definitions`. This also allows to create `InvocationData` entries in resolve when the data is actually ready, and remove cells and "uninitialized" variants from it. --- src/librustc/hir/map/def_collector.rs | 33 ++-------- src/librustc/hir/map/definitions.rs | 13 ++++ src/librustc/hir/map/mod.rs | 2 +- src/librustc_resolve/build_reduced_graph.rs | 19 ++++-- src/librustc_resolve/lib.rs | 5 +- src/librustc_resolve/macros.rs | 70 +++++++-------------- 6 files changed, 55 insertions(+), 87 deletions(-) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index 41073773e9f9b..f946ca2903ac8 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -1,6 +1,5 @@ use crate::hir::map::definitions::*; -use crate::hir::def_id::{CRATE_DEF_INDEX, DefIndex}; -use crate::session::CrateDisambiguator; +use crate::hir::def_id::DefIndex; use syntax::ast::*; use syntax::ext::hygiene::Mark; @@ -14,31 +13,12 @@ pub struct DefCollector<'a> { definitions: &'a mut Definitions, parent_def: Option, expansion: Mark, - pub visit_macro_invoc: Option<&'a mut dyn FnMut(MacroInvocationData)>, -} - -pub struct MacroInvocationData { - pub mark: Mark, - pub def_index: DefIndex, } impl<'a> DefCollector<'a> { pub fn new(definitions: &'a mut Definitions, expansion: Mark) -> Self { - DefCollector { - definitions, - expansion, - parent_def: None, - visit_macro_invoc: None, - } - } - - pub fn collect_root(&mut self, - crate_name: &str, - crate_disambiguator: CrateDisambiguator) { - let root = self.definitions.create_root_def(crate_name, - crate_disambiguator); - assert_eq!(root, CRATE_DEF_INDEX); - self.parent_def = Some(root); + let parent_def = Some(definitions.invocation_parent(expansion)); + DefCollector { definitions, parent_def, expansion } } fn create_def(&mut self, @@ -97,12 +77,7 @@ impl<'a> DefCollector<'a> { } fn visit_macro_invoc(&mut self, id: NodeId) { - if let Some(ref mut visit) = self.visit_macro_invoc { - visit(MacroInvocationData { - mark: id.placeholder_to_mark(), - def_index: self.parent_def.unwrap(), - }) - } + self.definitions.set_invocation_parent(id.placeholder_to_mark(), self.parent_def.unwrap()); } } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 9e7898e10b011..9188a78e489ef 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -100,6 +100,9 @@ pub struct Definitions { expansions_that_defined: FxHashMap, next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>, def_index_to_span: FxHashMap, + /// When collecting definitions from an AST fragment produced by a macro invocation `Mark` + /// we know what parent node that fragment should be attached to thanks to this table. + invocation_parents: FxHashMap, } /// A unique identifier that we can use to lookup a definition @@ -434,6 +437,7 @@ impl Definitions { assert!(self.def_index_to_node.is_empty()); self.def_index_to_node.push(ast::CRATE_NODE_ID); self.node_to_def_index.insert(ast::CRATE_NODE_ID, root_index); + self.set_invocation_parent(Mark::root(), root_index); // Allocate some other DefIndices that always must exist. GlobalMetaDataKind::allocate_def_indices(self); @@ -526,6 +530,15 @@ impl Definitions { pub fn add_parent_module_of_macro_def(&mut self, mark: Mark, module: DefId) { self.parent_modules_of_macro_defs.insert(mark, module); } + + pub fn invocation_parent(&self, invoc_id: Mark) -> DefIndex { + self.invocation_parents[&invoc_id] + } + + pub fn set_invocation_parent(&mut self, invoc_id: Mark, parent: DefIndex) { + let old_parent = self.invocation_parents.insert(invoc_id, parent); + assert!(old_parent.is_none(), "parent def-index is reset for an invocation"); + } } impl DefPathData { diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 63f60d0ab9528..f9092196ab3cd 100644 --- a/src/librustc/hir/map/mod.rs +++ b/src/librustc/hir/map/mod.rs @@ -1,5 +1,5 @@ use self::collector::NodeCollector; -pub use self::def_collector::{DefCollector, MacroInvocationData}; +pub use self::def_collector::DefCollector; pub use self::definitions::{ Definitions, DefKey, DefPath, DefPathData, DisambiguatedDefPathData, DefPathHash }; diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 974487ab9d2d7..8515029193e9b 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -944,12 +944,19 @@ pub struct BuildReducedGraphVisitor<'a, 'b> { impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { fn visit_invoc(&mut self, id: ast::NodeId) -> &'b InvocationData<'b> { - let mark = id.placeholder_to_mark(); - self.resolver.current_module.unresolved_invocations.borrow_mut().insert(mark); - let invocation = self.resolver.invocations[&mark]; - invocation.module.set(self.resolver.current_module); - invocation.parent_legacy_scope.set(self.current_legacy_scope); - invocation + let invoc_id = id.placeholder_to_mark(); + + self.resolver.current_module.unresolved_invocations.borrow_mut().insert(invoc_id); + + let invocation_data = self.resolver.arenas.alloc_invocation_data(InvocationData { + module: self.resolver.current_module, + parent_legacy_scope: self.current_legacy_scope, + output_legacy_scope: Cell::new(None), + }); + let old_invocation_data = self.resolver.invocations.insert(invoc_id, invocation_data); + assert!(old_invocation_data.is_none(), "invocation data is reset for an invocation"); + + invocation_data } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 207b0b3754ac6..09d7d8ace6bc0 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -19,7 +19,7 @@ use GenericParameters::*; use RibKind::*; use smallvec::smallvec; -use rustc::hir::map::{Definitions, DefCollector}; +use rustc::hir::map::Definitions; use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str}; use rustc::middle::cstore::CrateStore; use rustc::session::Session; @@ -1901,8 +1901,7 @@ impl<'a> Resolver<'a> { module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root); let mut definitions = Definitions::default(); - DefCollector::new(&mut definitions, Mark::root()) - .collect_root(crate_name, session.local_crate_disambiguator()); + definitions.create_root_def(crate_name, session.local_crate_disambiguator()); let mut extern_prelude: FxHashMap> = session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default())) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7f57b0a5052af..8361bbe45c483 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,7 +8,7 @@ use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; use crate::resolve_imports::ImportResolver; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; -use rustc::hir::map::{self, DefCollector}; +use rustc::hir::map::DefCollector; use rustc::middle::stability; use rustc::{ty, lint, span_bug}; use syntax::ast::{self, Ident}; @@ -32,14 +32,14 @@ use rustc_data_structures::sync::Lrc; type Res = def::Res; +// FIXME: Merge this with `ParentScope`. #[derive(Clone, Debug)] pub struct InvocationData<'a> { - def_index: DefIndex, /// The module in which the macro was invoked. - crate module: Cell>, + crate module: Module<'a>, /// The legacy scope in which the macro was invoked. /// The invocation path is resolved in this scope. - crate parent_legacy_scope: Cell>, + crate parent_legacy_scope: LegacyScope<'a>, /// The legacy scope *produced* by expanding this macro invocation, /// includes all the macro_rules items, other invocations, etc generated by it. /// `None` if the macro is not expanded yet. @@ -49,10 +49,9 @@ pub struct InvocationData<'a> { impl<'a> InvocationData<'a> { pub fn root(graph_root: Module<'a>) -> Self { InvocationData { - module: Cell::new(graph_root), - def_index: CRATE_DEF_INDEX, - parent_legacy_scope: Cell::new(LegacyScope::Empty), - output_legacy_scope: Cell::new(Some(LegacyScope::Empty)), + module: graph_root, + parent_legacy_scope: LegacyScope::Empty, + output_legacy_scope: Cell::new(None), } } } @@ -74,9 +73,6 @@ pub struct LegacyBinding<'a> { /// can potentially expand into macro definitions. #[derive(Copy, Clone, Debug)] pub enum LegacyScope<'a> { - /// Created when invocation data is allocated in the arena; - /// must be replaced with a proper scope later. - Uninitialized, /// Empty "root" scope at the crate start containing no names. Empty, /// The scope introduced by a `macro_rules!` macro definition. @@ -139,11 +135,11 @@ impl<'a> base::Resolver for Resolver<'a> { fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { let mark = Mark::fresh(Mark::root()); let module = self.module_map[&self.definitions.local_def_id(id)]; + self.definitions.set_invocation_parent(mark, module.def_id().unwrap().index); self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData { - module: Cell::new(module), - def_index: module.def_id().unwrap().index, - parent_legacy_scope: Cell::new(LegacyScope::Empty), - output_legacy_scope: Cell::new(Some(LegacyScope::Empty)), + module, + parent_legacy_scope: LegacyScope::Empty, + output_legacy_scope: Cell::new(None), })); mark } @@ -160,16 +156,20 @@ impl<'a> base::Resolver for Resolver<'a> { fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment, derives: &[Mark]) { - let invocation = self.invocations[&mark]; - self.collect_def_ids(mark, invocation, fragment); + fragment.visit_with(&mut DefCollector::new(&mut self.definitions, mark)); - self.current_module = invocation.module.get(); + let invocation = self.invocations[&mark]; + self.current_module = invocation.module; self.current_module.unresolved_invocations.borrow_mut().remove(&mark); self.current_module.unresolved_invocations.borrow_mut().extend(derives); + let parent_def = self.definitions.invocation_parent(mark); + for &derive_invoc_id in derives { + self.definitions.set_invocation_parent(derive_invoc_id, parent_def); + } self.invocations.extend(derives.iter().map(|&derive| (derive, invocation))); let mut visitor = BuildReducedGraphVisitor { resolver: self, - current_legacy_scope: invocation.parent_legacy_scope.get(), + current_legacy_scope: invocation.parent_legacy_scope, expansion: mark, }; fragment.visit_with(&mut visitor); @@ -259,9 +259,9 @@ impl<'a> Resolver<'a> { fn invoc_parent_scope(&self, invoc_id: Mark, derives: Vec) -> ParentScope<'a> { let invoc = self.invocations[&invoc_id]; ParentScope { - module: invoc.module.get().nearest_item_scope(), + module: invoc.module.nearest_item_scope(), expansion: invoc_id.parent(), - legacy: invoc.parent_legacy_scope.get(), + legacy: invoc.parent_legacy_scope, derives, } } @@ -829,10 +829,9 @@ impl<'a> Resolver<'a> { binding.parent_legacy_scope ), LegacyScope::Invocation(invoc) => WhereToResolve::MacroRules( - invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope.get()) + invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope) ), LegacyScope::Empty => WhereToResolve::Module(parent_scope.module), - LegacyScope::Uninitialized => unreachable!(), } WhereToResolve::CrateRoot => match ns { TypeNS => { @@ -1084,31 +1083,6 @@ impl<'a> Resolver<'a> { } } - fn collect_def_ids(&mut self, - mark: Mark, - invocation: &'a InvocationData<'a>, - fragment: &AstFragment) { - let Resolver { ref mut invocations, arenas, graph_root, .. } = *self; - let InvocationData { def_index, .. } = *invocation; - - let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| { - invocations.entry(invoc.mark).or_insert_with(|| { - arenas.alloc_invocation_data(InvocationData { - def_index: invoc.def_index, - module: Cell::new(graph_root), - parent_legacy_scope: Cell::new(LegacyScope::Uninitialized), - output_legacy_scope: Cell::new(None), - }) - }); - }; - - let mut def_collector = DefCollector::new(&mut self.definitions, mark); - def_collector.visit_macro_invoc = Some(visit_macro_invoc); - def_collector.with_parent(def_index, |def_collector| { - fragment.visit_with(def_collector) - }); - } - crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. From b392781edc145d1d1592c6d1bba4c33fbc1f51d5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 2 Jul 2019 23:42:00 +0300 Subject: [PATCH 21/37] def_collector: `parent_def` is no longer optional --- src/librustc/hir/map/def_collector.rs | 48 ++++++++++----------------- 1 file changed, 17 insertions(+), 31 deletions(-) diff --git a/src/librustc/hir/map/def_collector.rs b/src/librustc/hir/map/def_collector.rs index f946ca2903ac8..6b93bd96a2718 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -11,13 +11,13 @@ use syntax_pos::Span; /// Creates `DefId`s for nodes in the AST. pub struct DefCollector<'a> { definitions: &'a mut Definitions, - parent_def: Option, + parent_def: DefIndex, expansion: Mark, } impl<'a> DefCollector<'a> { pub fn new(definitions: &'a mut Definitions, expansion: Mark) -> Self { - let parent_def = Some(definitions.invocation_parent(expansion)); + let parent_def = definitions.invocation_parent(expansion); DefCollector { definitions, parent_def, expansion } } @@ -26,17 +26,15 @@ impl<'a> DefCollector<'a> { data: DefPathData, span: Span) -> DefIndex { - let parent_def = self.parent_def.unwrap(); + let parent_def = self.parent_def; debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); - self.definitions - .create_def_with_parent(parent_def, node_id, data, self.expansion, span) + self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span) } pub fn with_parent(&mut self, parent_def: DefIndex, f: F) { - let parent = self.parent_def; - self.parent_def = Some(parent_def); + let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def); f(self); - self.parent_def = parent; + self.parent_def = orig_parent_def; } fn visit_async_fn( @@ -77,7 +75,7 @@ impl<'a> DefCollector<'a> { } fn visit_macro_invoc(&mut self, id: NodeId) { - self.definitions.set_invocation_parent(id.placeholder_to_mark(), self.parent_def.unwrap()); + self.definitions.set_invocation_parent(id.placeholder_to_mark(), self.parent_def); } } @@ -250,36 +248,24 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } fn visit_expr(&mut self, expr: &'a Expr) { - let parent_def = self.parent_def; - - match expr.node { + let parent_def = match expr.node { ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id), ExprKind::Closure(_, asyncness, ..) => { - let closure_def = self.create_def(expr.id, - DefPathData::ClosureExpr, - expr.span); - self.parent_def = Some(closure_def); - // Async closures desugar to closures inside of closures, so // we must create two defs. - if let IsAsync::Async { closure_id, .. } = asyncness { - let async_def = self.create_def(closure_id, - DefPathData::ClosureExpr, - expr.span); - self.parent_def = Some(async_def); + let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span); + match asyncness { + IsAsync::Async { closure_id, .. } => + self.create_def(closure_id, DefPathData::ClosureExpr, expr.span), + IsAsync::NotAsync => closure_def, } } - ExprKind::Async(_, async_id, _) => { - let async_def = self.create_def(async_id, - DefPathData::ClosureExpr, - expr.span); - self.parent_def = Some(async_def); - } - _ => {} + ExprKind::Async(_, async_id, _) => + self.create_def(async_id, DefPathData::ClosureExpr, expr.span), + _ => self.parent_def, }; - visit::walk_expr(self, expr); - self.parent_def = parent_def; + self.with_parent(parent_def, |this| visit::walk_expr(this, expr)); } fn visit_ty(&mut self, ty: &'a Ty) { From cd0fd630e8170f8770485cb8248ff3d823521523 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 01:44:04 +0300 Subject: [PATCH 22/37] resolve: Make proc macro stubs less stubby Create real working and registered (even if dummy) `SyntaxExtension`s for them. This improves error recovery and allows to avoid all special cases for proc macro stubs (except for the error on use, of course). The introduced dummy `SyntaxExtension`s can be used for any other inappropriately resolved macros as well. --- src/librustc_resolve/build_reduced_graph.rs | 18 +---- src/librustc_resolve/lib.rs | 21 ++++- src/librustc_resolve/macros.rs | 76 +++++++++++++------ src/libsyntax/ext/base.rs | 22 +++++- .../proc-macro/macro-namespace-reserved-2.rs | 10 ++- .../macro-namespace-reserved-2.stderr | 66 ++++++++++------ 6 files changed, 138 insertions(+), 75 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 8515029193e9b..6fdd0c3ff3e4d 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -46,20 +46,6 @@ use log::debug; type Res = def::Res; -fn proc_macro_stub(item: &Item) -> Option<(Ident, Span)> { - if attr::contains_name(&item.attrs, sym::proc_macro) || - attr::contains_name(&item.attrs, sym::proc_macro_attribute) { - return Some((item.ident, item.span)); - } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = nested_meta.ident() { - return Some((ident, ident.span)); - } - } - } - None -} - impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { @@ -470,9 +456,7 @@ impl<'a> Resolver<'a> { // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). - if let Some((ident, span)) = proc_macro_stub(item) { - self.define(parent, ident, MacroNS, (res, vis, span, expansion)); - } + self.define_macro(item, expansion, &mut LegacyScope::Empty); } // These items live in the type namespace. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 09d7d8ace6bc0..b6c26b1a721e1 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -40,7 +40,7 @@ use rustc_metadata::cstore::CStore; use syntax::source_map::SourceMap; use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; -use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; +use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::base::MacroKind; use syntax::symbol::{Symbol, kw, sym}; @@ -1663,10 +1663,13 @@ pub struct Resolver<'a> { macro_use_prelude: FxHashMap>, pub all_macros: FxHashMap, macro_map: FxHashMap>, + dummy_ext_bang: Lrc, + dummy_ext_derive: Lrc, non_macro_attrs: [Lrc; 2], macro_defs: FxHashMap, local_macro_def_scopes: FxHashMap>, unused_macros: NodeMap, + proc_macro_stubs: NodeSet, /// Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap>, @@ -1925,9 +1928,8 @@ impl<'a> Resolver<'a> { macro_defs.insert(Mark::root(), root_def_id); let features = session.features_untracked(); - let non_macro_attr = |mark_used| Lrc::new(SyntaxExtension::default( - SyntaxExtensionKind::NonMacroAttr { mark_used }, session.edition() - )); + let non_macro_attr = + |mark_used| Lrc::new(SyntaxExtension::non_macro_attr(mark_used, session.edition())); Resolver { session, @@ -2002,6 +2004,8 @@ impl<'a> Resolver<'a> { macro_use_prelude: FxHashMap::default(), all_macros: FxHashMap::default(), macro_map: FxHashMap::default(), + dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())), + dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())), non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)], invocations, macro_defs, @@ -2010,6 +2014,7 @@ impl<'a> Resolver<'a> { potentially_unused_imports: Vec::new(), struct_constructors: Default::default(), unused_macros: Default::default(), + proc_macro_stubs: Default::default(), current_type_ascription: Vec::new(), injected_crate: None, active_features: @@ -2027,6 +2032,14 @@ impl<'a> Resolver<'a> { self.non_macro_attrs[mark_used as usize].clone() } + fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc { + match macro_kind { + MacroKind::Bang => self.dummy_ext_bang.clone(), + MacroKind::Derive => self.dummy_ext_derive.clone(), + MacroKind::Attr => self.non_macro_attr(true), + } + } + /// Runs the function on each namespace. fn per_ns(&mut self, mut f: F) { f(self, TypeNS); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 8361bbe45c483..20eb97c15ba73 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -11,7 +11,7 @@ use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::map::DefCollector; use rustc::middle::stability; use rustc::{ty, lint, span_bug}; -use syntax::ast::{self, Ident}; +use syntax::ast::{self, Ident, ItemKind}; use syntax::attr::{self, StabilityLevel}; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy}; @@ -127,6 +127,21 @@ fn fast_print_path(path: &ast::Path) -> Symbol { } } +fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { + if attr::contains_name(&item.attrs, sym::proc_macro) { + return Some((MacroKind::Bang, item.ident, item.span)); + } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { + return Some((MacroKind::Attr, item.ident, item.span)); + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { + if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { + if let Some(ident) = nested_meta.ident() { + return Some((MacroKind::Derive, ident, ident.span)); + } + } + } + None +} + impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -216,10 +231,9 @@ impl<'a> base::Resolver for Resolver<'a> { let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) { Ok((res, ext)) => (res, ext), - // Replace unresolved attributes with used inert attributes for better recovery. - Err(Determinacy::Determined) if kind == MacroKind::Attr => - (Res::Err, self.non_macro_attr(true)), - Err(determinacy) => return Err(determinacy), + // Return dummy syntax extensions for unresolved macros for better recovery. + Err(Determinacy::Determined) => (Res::Err, self.dummy_ext(kind)), + Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), }; let span = invoc.span(); @@ -305,13 +319,14 @@ impl<'a> Resolver<'a> { Res::Def(DefKind::Macro(_), def_id) => { if let Some(node_id) = self.definitions.as_local_node_id(def_id) { self.unused_macros.remove(&node_id); + if self.proc_macro_stubs.contains(&node_id) { + self.session.span_err( + path.span, + "can't use a procedural macro from the same crate that defines it", + ); + } } } - Res::Def(DefKind::Fn, _) => { - let msg = "can't use a procedural macro from the same crate that defines it"; - self.session.span_err(path.span, msg); - return Err(Determinacy::Determined); - } Res::NonMacroAttr(attr_kind) => { if kind == MacroKind::Attr { if attr_kind == NonMacroAttrKind::Custom { @@ -1100,19 +1115,32 @@ impl<'a> Resolver<'a> { item: &ast::Item, expansion: Mark, current_legacy_scope: &mut LegacyScope<'a>) { - self.local_macro_def_scopes.insert(item.id, self.current_module); - let ident = item.ident; + let (ext, ident, span, is_legacy) = match &item.node { + ItemKind::MacroDef(def) => { + let ext = Lrc::new(macro_rules::compile( + &self.session.parse_sess, + &self.session.features_untracked(), + item, + self.session.edition(), + )); + (ext, item.ident, item.span, def.legacy) + } + ItemKind::Fn(..) => match proc_macro_stub(item) { + Some((macro_kind, ident, span)) => { + self.proc_macro_stubs.insert(item.id); + (self.dummy_ext(macro_kind), ident, span, false) + } + None => return, + } + _ => unreachable!(), + }; 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, self.session.edition())); - let macro_kind = ext.macro_kind(); - let res = Res::Def(DefKind::Macro(macro_kind), def_id); + let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id); self.macro_map.insert(def_id, ext); + self.local_macro_def_scopes.insert(item.id, self.current_module); - let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() }; - if def.legacy { + if is_legacy { let ident = ident.modern(); self.macro_names.insert(ident); let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); @@ -1121,7 +1149,7 @@ impl<'a> Resolver<'a> { } else { ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) }; - let binding = (res, vis, item.span, expansion).to_name_binding(self.arenas); + let binding = (res, vis, span, expansion).to_name_binding(self.arenas); self.set_binding_parent_module(binding, self.current_module); let legacy_binding = self.arenas.alloc_legacy_binding(LegacyBinding { parent_legacy_scope: *current_legacy_scope, binding, ident @@ -1131,18 +1159,18 @@ impl<'a> Resolver<'a> { if is_macro_export { let module = self.graph_root; self.define(module, ident, MacroNS, - (res, vis, item.span, expansion, IsMacroExport)); + (res, vis, span, expansion, IsMacroExport)); } else { self.check_reserved_macro_name(ident, res); - self.unused_macros.insert(item.id, item.span); + self.unused_macros.insert(item.id, span); } } else { let module = self.current_module; let vis = self.resolve_visibility(&item.vis); if vis != ty::Visibility::Public { - self.unused_macros.insert(item.id, item.span); + self.unused_macros.insert(item.id, span); } - self.define(module, ident, MacroNS, (res, vis, item.span, expansion)); + self.define(module, ident, MacroNS, (res, vis, span, expansion)); } } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 04f124685cbb5..82386b78f1dc2 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -10,7 +10,7 @@ use crate::parse::token; use crate::ptr::P; use crate::symbol::{kw, sym, Ident, Symbol}; use crate::{ThinVec, MACRO_ARGUMENTS}; -use crate::tokenstream::{self, TokenStream}; +use crate::tokenstream::{self, TokenStream, TokenTree}; use errors::{DiagnosticBuilder, DiagnosticId}; use smallvec::{smallvec, SmallVec}; @@ -640,6 +640,26 @@ impl SyntaxExtension { } } + pub fn dummy_bang(edition: Edition) -> SyntaxExtension { + fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree]) + -> Box { + DummyResult::any(span) + } + SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition) + } + + pub fn dummy_derive(edition: Edition) -> SyntaxExtension { + fn expander(_: &mut ExtCtxt<'_>, _: Span, _: &ast::MetaItem, _: Annotatable) + -> Vec { + Vec::new() + } + SyntaxExtension::default(SyntaxExtensionKind::Derive(Box::new(expander)), edition) + } + + pub fn non_macro_attr(mark_used: bool, edition: Edition) -> SyntaxExtension { + SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition) + } + pub fn expn_info(&self, call_site: Span, descr: Symbol) -> ExpnInfo { ExpnInfo { call_site, diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs index 583640aa8171c..c7b092830a243 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs @@ -25,22 +25,24 @@ fn check_bang1() { my_macro!(); //~ ERROR can't use a procedural macro from the same crate that defines it } fn check_bang2() { - my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines it + my_macro_attr!(); //~ ERROR cannot find macro `my_macro_attr!` in this scope } fn check_bang3() { - MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it + MyTrait!(); //~ ERROR cannot find macro `MyTrait!` in this scope } -#[my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it +#[my_macro] //~ ERROR attribute `my_macro` is currently unknown fn check_attr1() {} #[my_macro_attr] //~ ERROR can't use a procedural macro from the same crate that defines it fn check_attr2() {} #[MyTrait] //~ ERROR can't use a procedural macro from the same crate that defines it + //~| ERROR `MyTrait` is a derive macro fn check_attr3() {} -#[derive(my_macro)] //~ ERROR can't use a procedural macro from the same crate that defines it +#[derive(my_macro)] //~ ERROR cannot find derive macro `my_macro` in this scope struct CheckDerive1; #[derive(my_macro_attr)] //~ ERROR can't use a procedural macro from the same crate that defines it + //~| ERROR macro `my_macro_attr` may not be used for derive attributes struct CheckDerive2; #[derive(MyTrait)] //~ ERROR can't use a procedural macro from the same crate that defines it struct CheckDerive3; diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr index 548f9e3051dd3..83c77513ec3bf 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -4,24 +4,6 @@ error: can't use a procedural macro from the same crate that defines it LL | my_macro!(); | ^^^^^^^^ -error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:28:5 - | -LL | my_macro_attr!(); - | ^^^^^^^^^^^^^ - -error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:31:5 - | -LL | MyTrait!(); - | ^^^^^^^ - -error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:34:3 - | -LL | #[my_macro] - | ^^^^^^^^ - error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:36:3 | @@ -34,23 +16,57 @@ error: can't use a procedural macro from the same crate that defines it LL | #[MyTrait] | ^^^^^^^ -error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:41:10 +error: `MyTrait` is a derive macro + --> $DIR/macro-namespace-reserved-2.rs:38:1 | -LL | #[derive(my_macro)] - | ^^^^^^^^ +LL | #[MyTrait] + | ^^^^^^^^^^ error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:43:10 + --> $DIR/macro-namespace-reserved-2.rs:44:10 + | +LL | #[derive(my_macro_attr)] + | ^^^^^^^^^^^^^ + +error: macro `my_macro_attr` may not be used for derive attributes + --> $DIR/macro-namespace-reserved-2.rs:44:10 | LL | #[derive(my_macro_attr)] | ^^^^^^^^^^^^^ error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:45:10 + --> $DIR/macro-namespace-reserved-2.rs:47:10 | LL | #[derive(MyTrait)] | ^^^^^^^ -error: aborting due to 9 previous errors +error[E0658]: The attribute `my_macro` is currently unknown to the compiler and may have meaning added to it in the future + --> $DIR/macro-namespace-reserved-2.rs:34:3 + | +LL | #[my_macro] + | ^^^^^^^^ + | + = note: for more information, see https://github.com/rust-lang/rust/issues/29642 + = help: add #![feature(custom_attribute)] to the crate attributes to enable + +error: cannot find derive macro `my_macro` in this scope + --> $DIR/macro-namespace-reserved-2.rs:42:10 + | +LL | #[derive(my_macro)] + | ^^^^^^^^ + +error: cannot find macro `my_macro_attr!` in this scope + --> $DIR/macro-namespace-reserved-2.rs:28:5 + | +LL | my_macro_attr!(); + | ^^^^^^^^^^^^^ + +error: cannot find macro `MyTrait!` in this scope + --> $DIR/macro-namespace-reserved-2.rs:31:5 + | +LL | MyTrait!(); + | ^^^^^^^ + +error: aborting due to 11 previous errors +For more information about this error, try `rustc --explain E0658`. From f16993d4acaf90285f6c86268a0ec2e7167c2a58 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 11:44:57 +0300 Subject: [PATCH 23/37] resolve/expand: `resolve_macro_invocation` no longer returns determinate errors It either returns the indeterminacy error, or valid (but perhaps dummy) `SyntaxExtension`. With this change enum `Determinacy` is no longer used in libsyntax and can be moved to resolve. The regressions in diagnosics are fixed in the next commits. --- src/librustc_resolve/build_reduced_graph.rs | 9 +- src/librustc_resolve/lib.rs | 14 ++- src/librustc_resolve/macros.rs | 66 +++++------ src/librustc_resolve/resolve_imports.rs | 2 +- src/libsyntax/ext/base.rs | 17 +-- src/libsyntax/ext/expand.rs | 111 +++++++++--------- .../ui/macros/macro-path-prelude-fail-4.rs | 2 +- .../macros/macro-path-prelude-fail-4.stderr | 2 +- .../tool-attributes-misplaced-2.rs | 4 +- .../tool-attributes-misplaced-2.stderr | 4 +- 10 files changed, 108 insertions(+), 123 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6fdd0c3ff3e4d..f74d07a3c5ee6 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -9,7 +9,7 @@ use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleIm use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; use crate::{ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry}; use crate::Namespace::{self, TypeNS, ValueNS, MacroNS}; -use crate::{resolve_error, resolve_struct_error, ResolutionError}; +use crate::{resolve_error, resolve_struct_error, ResolutionError, Determinacy}; use rustc::bug; use rustc::hir::def::{self, *}; @@ -30,7 +30,6 @@ use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant}; use syntax::ext::base::SyntaxExtension; -use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::feature_gate::is_builtin_attr; @@ -231,9 +230,9 @@ impl<'a> Resolver<'a> { source: source.ident, target: ident, source_bindings: PerNS { - type_ns: Cell::new(Err(Undetermined)), - value_ns: Cell::new(Err(Undetermined)), - macro_ns: Cell::new(Err(Undetermined)), + type_ns: Cell::new(Err(Determinacy::Undetermined)), + value_ns: Cell::new(Err(Determinacy::Undetermined)), + macro_ns: Cell::new(Err(Determinacy::Undetermined)), }, target_bindings: PerNS { type_ns: Cell::new(None), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b6c26b1a721e1..795ff3faffa33 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -15,6 +15,7 @@ pub use rustc::hir::def::{Namespace, PerNS}; +use Determinacy::*; use GenericParameters::*; use RibKind::*; use smallvec::smallvec; @@ -41,7 +42,6 @@ use syntax::source_map::SourceMap; use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; use syntax::ext::base::SyntaxExtension; -use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::base::MacroKind; use syntax::symbol::{Symbol, kw, sym}; use syntax::util::lev_distance::find_best_match_for_name; @@ -93,6 +93,18 @@ enum Weak { No, } +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Determinacy { + Determined, + Undetermined, +} + +impl Determinacy { + fn determined(determined: bool) -> Determinacy { + if determined { Determinacy::Determined } else { Determinacy::Undetermined } + } +} + enum ScopeSet { Import(Namespace), AbsolutePath(Namespace), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 20eb97c15ba73..905b3347a5470 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -1,4 +1,4 @@ -use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc}; +use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy}; use crate::{CrateLint, Resolver, ResolutionError, ScopeSet, Weak}; use crate::{Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding}; use crate::{is_known_tool, resolve_error}; @@ -14,7 +14,7 @@ use rustc::{ty, lint, span_bug}; use syntax::ast::{self, Ident, ItemKind}; use syntax::attr::{self, StabilityLevel}; use syntax::errors::DiagnosticBuilder; -use syntax::ext::base::{self, Determinacy}; +use syntax::ext::base::{self, Indeterminate}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; use syntax::ext::hygiene::{self, Mark}; @@ -216,7 +216,7 @@ impl<'a> base::Resolver for Resolver<'a> { } fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) - -> Result>, Determinacy> { + -> Result>, Indeterminate> { let (path, kind, derives_in_scope, after_derive) = match invoc.kind { InvocationKind::Attr { attr: None, .. } => return Ok(None), @@ -229,12 +229,7 @@ impl<'a> base::Resolver for Resolver<'a> { }; let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) { - Ok((res, ext)) => (res, ext), - // Return dummy syntax extensions for unresolved macros for better recovery. - Err(Determinacy::Determined) => (Res::Err, self.dummy_ext(kind)), - Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), - }; + let (res, ext) = self.resolve_macro_to_res(path, kind, &parent_scope, true, force)?; let span = invoc.span(); let descr = fast_print_path(path); @@ -287,7 +282,7 @@ impl<'a> Resolver<'a> { parent_scope: &ParentScope<'a>, trace: bool, force: bool, - ) -> Result<(Res, Lrc), Determinacy> { + ) -> Result<(Res, Lrc), Indeterminate> { let res = self.resolve_macro_to_res_inner(path, kind, parent_scope, trace, force); // Report errors and enforce feature gates for the resolved macro. @@ -313,7 +308,14 @@ impl<'a> Resolver<'a> { } } - let res = res?; + let res = match res { + Err(Determinacy::Undetermined) => return Err(Indeterminate), + Ok(Res::Err) | Err(Determinacy::Determined) => { + // Return dummy syntax extensions for unresolved macros for better recovery. + return Ok((Res::Err, self.dummy_ext(kind))); + } + Ok(res) => res, + }; match res { Res::Def(DefKind::Macro(_), def_id) => { @@ -328,35 +330,23 @@ impl<'a> Resolver<'a> { } } Res::NonMacroAttr(attr_kind) => { - if kind == MacroKind::Attr { - if attr_kind == NonMacroAttrKind::Custom { - assert!(path.segments.len() == 1); - if !features.custom_attribute { - let msg = format!("The attribute `{}` is currently unknown to the \ - compiler and may have meaning added to it in the \ - future", path); - self.report_unknown_attribute( - path.span, - &path.segments[0].ident.as_str(), - &msg, - sym::custom_attribute, - ); - } + if attr_kind == NonMacroAttrKind::Custom { + assert!(path.segments.len() == 1); + if !features.custom_attribute { + let msg = format!("The attribute `{}` is currently unknown to the \ + compiler and may have meaning added to it in the \ + future", path); + self.report_unknown_attribute( + path.span, + &path.segments[0].ident.as_str(), + &msg, + sym::custom_attribute, + ); } - } else { - // Not only attributes, but anything in macro namespace can result in - // `Res::NonMacroAttr` definition (e.g., `inline!()`), so we must report - // an error for those cases. - let msg = format!("expected a macro, found {}", res.descr()); - self.session.span_err(path.span, &msg); - return Err(Determinacy::Determined); } } - Res::Err => { - return Err(Determinacy::Determined); - } _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), - } + }; Ok((res, self.get_macro(res))) } @@ -608,9 +598,7 @@ impl<'a> Resolver<'a> { result = Ok((binding, Flags::empty())); break; } - Err(Determinacy::Determined) => {} - Err(Determinacy::Undetermined) => - result = Err(Determinacy::Undetermined), + Err(Indeterminate) => result = Err(Determinacy::Undetermined), } } result diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 7de1cd29a9ca8..5edfe923e68a2 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -2,6 +2,7 @@ use ImportDirectiveSubclass::*; use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc}; use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, Weak}; +use crate::Determinacy::{self, *}; use crate::Namespace::{self, TypeNS, MacroNS}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; use crate::{Resolver, Segment}; @@ -27,7 +28,6 @@ use rustc::util::nodemap::FxHashSet; use rustc::{bug, span_bug}; use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID}; -use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; use syntax::symbol::kw; use syntax::util::lev_distance::find_best_match_for_name; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 82386b78f1dc2..cb4edee30cdbf 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -676,6 +676,9 @@ impl SyntaxExtension { pub type NamedSyntaxExtension = (Name, SyntaxExtension); +/// Error type that denotes indeterminacy. +pub struct Indeterminate; + pub trait Resolver { fn next_node_id(&mut self) -> ast::NodeId; @@ -689,23 +692,11 @@ pub trait Resolver { fn resolve_imports(&mut self); fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) - -> Result>, Determinacy>; + -> Result>, Indeterminate>; fn check_unused_macros(&self); } -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum Determinacy { - Determined, - Undetermined, -} - -impl Determinacy { - pub fn determined(determined: bool) -> Determinacy { - if determined { Determinacy::Determined } else { Determinacy::Undetermined } - } -} - #[derive(Clone)] pub struct ModuleData { pub mod_path: Vec, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 06ff2bc655cf5..2f7fb79a7f539 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -313,9 +313,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let scope = if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; let ext = match self.cx.resolver.resolve_macro_invocation(&invoc, scope, force) { - Ok(ext) => Some(ext), - Err(Determinacy::Determined) => None, - Err(Determinacy::Undetermined) => { + Ok(ext) => ext, + Err(Indeterminate) => { undetermined_invocations.push(invoc); continue } @@ -328,65 +327,61 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion.mark = scope; // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { - if let Some(ext) = ext { - let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); - let fragment = self.expand_invoc(invoc, &*ext).unwrap_or_else(|| { - invoc_fragment_kind.dummy(invoc_span).unwrap() - }); - self.collect_invocations(fragment, &[]) - } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { - if !item.derive_allowed() { - let attr = attr::find_by_name(item.attrs(), sym::derive) - .expect("`derive` attribute should exist"); - let span = attr.span; - let mut err = self.cx.mut_span_err(span, - "`derive` may only be applied to \ - structs, enums and unions"); - if let ast::AttrStyle::Inner = attr.style { - let trait_list = traits.iter() - .map(|t| t.to_string()).collect::>(); - let suggestion = format!("#[derive({})]", trait_list.join(", ")); - err.span_suggestion( - span, "try an outer attribute", suggestion, - // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT - Applicability::MaybeIncorrect - ); - } - err.emit(); + let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); + let fragment = self.expand_invoc(invoc, &*ext).unwrap_or_else(|| { + invoc_fragment_kind.dummy(invoc_span).unwrap() + }); + self.collect_invocations(fragment, &[]) + } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { + if !item.derive_allowed() { + let attr = attr::find_by_name(item.attrs(), sym::derive) + .expect("`derive` attribute should exist"); + let span = attr.span; + let mut err = self.cx.mut_span_err(span, + "`derive` may only be applied to \ + structs, enums and unions"); + if let ast::AttrStyle::Inner = attr.style { + let trait_list = traits.iter() + .map(|t| t.to_string()).collect::>(); + let suggestion = format!("#[derive({})]", trait_list.join(", ")); + err.span_suggestion( + span, "try an outer attribute", suggestion, + // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT + Applicability::MaybeIncorrect + ); } + err.emit(); + } - let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); - let mut item_with_markers = item.clone(); - add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers); - let derives = derives.entry(invoc.expansion_data.mark).or_default(); - - derives.reserve(traits.len()); - invocations.reserve(traits.len()); - for path in traits { - let mark = Mark::fresh(self.cx.current_expansion.mark); - derives.push(mark); - invocations.push(Invocation { - kind: InvocationKind::Derive { - path, - item: item.clone(), - item_with_markers: item_with_markers.clone(), - }, - fragment_kind: invoc.fragment_kind, - expansion_data: ExpansionData { - mark, - ..invoc.expansion_data.clone() - }, - }); - } - let fragment = invoc.fragment_kind - .expect_from_annotatables(::std::iter::once(item_with_markers)); - self.collect_invocations(fragment, derives) - } else { - unreachable!() + let mut item = self.fully_configure(item); + item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); + let mut item_with_markers = item.clone(); + add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers); + let derives = derives.entry(invoc.expansion_data.mark).or_default(); + + derives.reserve(traits.len()); + invocations.reserve(traits.len()); + for path in traits { + let mark = Mark::fresh(self.cx.current_expansion.mark); + derives.push(mark); + invocations.push(Invocation { + kind: InvocationKind::Derive { + path, + item: item.clone(), + item_with_markers: item_with_markers.clone(), + }, + fragment_kind: invoc.fragment_kind, + expansion_data: ExpansionData { + mark, + ..invoc.expansion_data.clone() + }, + }); } + let fragment = invoc.fragment_kind + .expect_from_annotatables(::std::iter::once(item_with_markers)); + self.collect_invocations(fragment, derives) } else { - self.collect_invocations(invoc.fragment_kind.dummy(invoc.span()).unwrap(), &[]) + unreachable!() }; if expanded_fragments.len() < depth { diff --git a/src/test/ui/macros/macro-path-prelude-fail-4.rs b/src/test/ui/macros/macro-path-prelude-fail-4.rs index 283427b9acefe..44f0f2d7ec03c 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-4.rs +++ b/src/test/ui/macros/macro-path-prelude-fail-4.rs @@ -1,4 +1,4 @@ -#[derive(inline)] //~ ERROR expected a macro, found built-in attribute +#[derive(inline)] //~ ERROR macro `inline` may not be used for derive attributes struct S; fn main() {} diff --git a/src/test/ui/macros/macro-path-prelude-fail-4.stderr b/src/test/ui/macros/macro-path-prelude-fail-4.stderr index f08445e1f775e..fdd7bf3235c14 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-4.stderr +++ b/src/test/ui/macros/macro-path-prelude-fail-4.stderr @@ -1,4 +1,4 @@ -error: expected a macro, found built-in attribute +error: macro `inline` may not be used for derive attributes --> $DIR/macro-path-prelude-fail-4.rs:1:10 | LL | #[derive(inline)] diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.rs b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.rs index 56b908d94cc88..b95791f4e99d8 100644 --- a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.rs +++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.rs @@ -1,6 +1,6 @@ -#[derive(rustfmt::skip)] //~ ERROR expected a macro, found tool attribute +#[derive(rustfmt::skip)] //~ ERROR macro `rustfmt::skip` may not be used for derive attributes struct S; fn main() { - rustfmt::skip!(); //~ ERROR expected a macro, found tool attribute + rustfmt::skip!(); //~ ERROR `rustfmt::skip` can only be used in attributes } diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr index c5f5f59c32c30..8ef27a07b7f8e 100644 --- a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr +++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr @@ -1,10 +1,10 @@ -error: expected a macro, found tool attribute +error: macro `rustfmt::skip` may not be used for derive attributes --> $DIR/tool-attributes-misplaced-2.rs:1:10 | LL | #[derive(rustfmt::skip)] | ^^^^^^^^^^^^^ -error: expected a macro, found tool attribute +error: `rustfmt::skip` can only be used in attributes --> $DIR/tool-attributes-misplaced-2.rs:5:5 | LL | rustfmt::skip!(); From 3041ec61185d6f9795ff16cc345e8f11b06edbbf Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 12:47:24 +0300 Subject: [PATCH 24/37] resolve/expand: Catch macro kind mismatches early in resolve This way we are processing all of them in a single point, rather than separately for each syntax extension kind. Also, the standard expected/found wording is used. --- src/librustc_resolve/macros.rs | 13 +++- src/libsyntax/ext/expand.rs | 39 ++-------- .../feature-gates/feature-gate-rustc-attrs.rs | 4 +- .../feature-gate-rustc-attrs.stderr | 12 +-- .../ui/macros/macro-path-prelude-fail-4.rs | 2 +- .../macros/macro-path-prelude-fail-4.stderr | 4 +- .../proc-macro/macro-namespace-reserved-2.rs | 12 ++- .../macro-namespace-reserved-2.stderr | 76 +++++++++++++++---- .../tool-attributes-misplaced-2.rs | 4 +- .../tool-attributes-misplaced-2.stderr | 8 +- 10 files changed, 106 insertions(+), 68 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 905b3347a5470..30969948c4c8c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -348,7 +348,18 @@ impl<'a> Resolver<'a> { _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), }; - Ok((res, self.get_macro(res))) + let ext = self.get_macro(res); + Ok(if ext.macro_kind() != kind { + let expected = if kind == MacroKind::Attr { "attribute" } else { kind.descr() }; + let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path); + self.session.struct_span_err(path.span, &msg) + .span_label(path.span, format!("not {} {}", kind.article(), expected)) + .emit(); + // Return dummy syntax extensions for unexpected macro kinds for better recovery. + (Res::Err, self.dummy_ext(kind)) + } else { + (res, ext) + }) } fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: Symbol) { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 2f7fb79a7f539..2349382eb5e9b 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -323,12 +323,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { progress = true; let ExpansionData { depth, mark, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); - self.cx.current_expansion.mark = scope; + // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); - let fragment = self.expand_invoc(invoc, &*ext).unwrap_or_else(|| { + let fragment = self.expand_invoc(invoc, &ext).unwrap_or_else(|| { invoc_fragment_kind.dummy(invoc_span).unwrap() }); self.collect_invocations(fragment, &[]) @@ -551,17 +551,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.gate_proc_macro_expansion(attr.span, &res); res } - SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => { - self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path)); - self.cx.trace_macros_diag(); - invoc.fragment_kind.dummy(attr.span) - } - _ => { - let msg = &format!("macro `{}` may not be used in attributes", attr.path); - self.cx.span_err(attr.span, msg); - self.cx.trace_macros_diag(); - invoc.fragment_kind.dummy(attr.span) - } + _ => unreachable!() } } @@ -671,21 +661,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let tok_result = expander.expand(self.cx, span, mac.node.stream()); kind.make_from(tok_result) } - - SyntaxExtensionKind::Attr(..) | - SyntaxExtensionKind::LegacyAttr(..) | - SyntaxExtensionKind::NonMacroAttr { .. } => { - self.cx.span_err(path.span, - &format!("`{}` can only be used in attributes", path)); - self.cx.trace_macros_diag(); - kind.dummy(span) - } - - SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => { - self.cx.span_err(path.span, &format!("`{}` is a derive macro", path)); - self.cx.trace_macros_diag(); - kind.dummy(span) - } + _ => unreachable!() }; if opt_expanded.is_some() { @@ -747,12 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let items = expander.expand(self.cx, span, &meta, item); Some(invoc.fragment_kind.expect_from_annotatables(items)) } - _ => { - let msg = &format!("macro `{}` may not be used for derive attributes", path); - self.cx.span_err(path.span, msg); - self.cx.trace_macros_diag(); - invoc.fragment_kind.dummy(path.span) - } + _ => unreachable!() } } diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs index d3a2e486416af..9ce2fb58ab0ad 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs @@ -7,12 +7,12 @@ mod unknown { pub macro rustc() {} } #[rustc::unknown] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler -//~| ERROR macro `rustc::unknown` may not be used in attributes +//~| ERROR expected attribute, found macro `rustc::unknown` fn f() {} #[unknown::rustc] //~^ ERROR attributes starting with `rustc` are reserved for use by the `rustc` compiler -//~| ERROR macro `unknown::rustc` may not be used in attributes +//~| ERROR expected attribute, found macro `unknown::rustc` fn g() {} #[rustc_dummy] diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr index f098635c70287..7c5aa5381e8c7 100644 --- a/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr +++ b/src/test/ui/feature-gates/feature-gate-rustc-attrs.stderr @@ -7,11 +7,11 @@ LL | #[rustc::unknown] = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable -error: macro `rustc::unknown` may not be used in attributes - --> $DIR/feature-gate-rustc-attrs.rs:8:1 +error: expected attribute, found macro `rustc::unknown` + --> $DIR/feature-gate-rustc-attrs.rs:8:3 | LL | #[rustc::unknown] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ not an attribute error[E0658]: attributes starting with `rustc` are reserved for use by the `rustc` compiler --> $DIR/feature-gate-rustc-attrs.rs:13:12 @@ -22,11 +22,11 @@ LL | #[unknown::rustc] = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable -error: macro `unknown::rustc` may not be used in attributes - --> $DIR/feature-gate-rustc-attrs.rs:13:1 +error: expected attribute, found macro `unknown::rustc` + --> $DIR/feature-gate-rustc-attrs.rs:13:3 | LL | #[unknown::rustc] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ not an attribute error[E0658]: attributes starting with `rustc` are reserved for use by the `rustc` compiler --> $DIR/feature-gate-rustc-attrs.rs:20:3 diff --git a/src/test/ui/macros/macro-path-prelude-fail-4.rs b/src/test/ui/macros/macro-path-prelude-fail-4.rs index 44f0f2d7ec03c..0f93fcdaa5f57 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-4.rs +++ b/src/test/ui/macros/macro-path-prelude-fail-4.rs @@ -1,4 +1,4 @@ -#[derive(inline)] //~ ERROR macro `inline` may not be used for derive attributes +#[derive(inline)] //~ ERROR expected derive macro, found built-in attribute `inline` struct S; fn main() {} diff --git a/src/test/ui/macros/macro-path-prelude-fail-4.stderr b/src/test/ui/macros/macro-path-prelude-fail-4.stderr index fdd7bf3235c14..dfd6818b6785a 100644 --- a/src/test/ui/macros/macro-path-prelude-fail-4.stderr +++ b/src/test/ui/macros/macro-path-prelude-fail-4.stderr @@ -1,8 +1,8 @@ -error: macro `inline` may not be used for derive attributes +error: expected derive macro, found built-in attribute `inline` --> $DIR/macro-path-prelude-fail-4.rs:1:10 | LL | #[derive(inline)] - | ^^^^^^ + | ^^^^^^ not a derive macro error: aborting due to previous error diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs index c7b092830a243..7a9e472c6c3ee 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs @@ -26,23 +26,31 @@ fn check_bang1() { } fn check_bang2() { my_macro_attr!(); //~ ERROR cannot find macro `my_macro_attr!` in this scope + crate::my_macro_attr!(); //~ ERROR can't use a procedural macro from the same crate that defines + //~| ERROR expected macro, found attribute macro `crate::my_macro_attr` } fn check_bang3() { MyTrait!(); //~ ERROR cannot find macro `MyTrait!` in this scope + crate::MyTrait!(); //~ ERROR can't use a procedural macro from the same crate that defines it + //~| ERROR expected macro, found derive macro `crate::MyTrait` } #[my_macro] //~ ERROR attribute `my_macro` is currently unknown +#[crate::my_macro] //~ ERROR can't use a procedural macro from the same crate that defines it + //~| ERROR expected attribute, found macro `crate::my_macro` fn check_attr1() {} #[my_macro_attr] //~ ERROR can't use a procedural macro from the same crate that defines it fn check_attr2() {} #[MyTrait] //~ ERROR can't use a procedural macro from the same crate that defines it - //~| ERROR `MyTrait` is a derive macro + //~| ERROR expected attribute, found derive macro `MyTrait` fn check_attr3() {} #[derive(my_macro)] //~ ERROR cannot find derive macro `my_macro` in this scope +#[derive(crate::my_macro)] //~ ERROR can't use a procedural macro from the same crate that defines + //~| ERROR expected derive macro, found macro `crate::my_macro` struct CheckDerive1; #[derive(my_macro_attr)] //~ ERROR can't use a procedural macro from the same crate that defines it - //~| ERROR macro `my_macro_attr` may not be used for derive attributes + //~| ERROR expected derive macro, found attribute macro `my_macro_attr` struct CheckDerive2; #[derive(MyTrait)] //~ ERROR can't use a procedural macro from the same crate that defines it struct CheckDerive3; diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr index 83c77513ec3bf..a724d388f4891 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -5,43 +5,79 @@ LL | my_macro!(); | ^^^^^^^^ error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:36:3 + --> $DIR/macro-namespace-reserved-2.rs:29:5 + | +LL | crate::my_macro_attr!(); + | ^^^^^^^^^^^^^^^^^^^^ + +error: expected macro, found attribute macro `crate::my_macro_attr` + --> $DIR/macro-namespace-reserved-2.rs:29:5 + | +LL | crate::my_macro_attr!(); + | ^^^^^^^^^^^^^^^^^^^^ not a macro + +error: can't use a procedural macro from the same crate that defines it + --> $DIR/macro-namespace-reserved-2.rs:34:5 + | +LL | crate::MyTrait!(); + | ^^^^^^^^^^^^^^ + +error: expected macro, found derive macro `crate::MyTrait` + --> $DIR/macro-namespace-reserved-2.rs:34:5 + | +LL | crate::MyTrait!(); + | ^^^^^^^^^^^^^^ not a macro + +error: can't use a procedural macro from the same crate that defines it + --> $DIR/macro-namespace-reserved-2.rs:42:3 | LL | #[my_macro_attr] | ^^^^^^^^^^^^^ error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:38:3 + --> $DIR/macro-namespace-reserved-2.rs:44:3 | LL | #[MyTrait] | ^^^^^^^ -error: `MyTrait` is a derive macro - --> $DIR/macro-namespace-reserved-2.rs:38:1 +error: expected attribute, found derive macro `MyTrait` + --> $DIR/macro-namespace-reserved-2.rs:44:3 | LL | #[MyTrait] - | ^^^^^^^^^^ + | ^^^^^^^ not an attribute error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:44:10 + --> $DIR/macro-namespace-reserved-2.rs:49:10 + | +LL | #[derive(crate::my_macro)] + | ^^^^^^^^^^^^^^^ + +error: expected derive macro, found macro `crate::my_macro` + --> $DIR/macro-namespace-reserved-2.rs:49:10 + | +LL | #[derive(crate::my_macro)] + | ^^^^^^^^^^^^^^^ not a derive macro + +error: can't use a procedural macro from the same crate that defines it + --> $DIR/macro-namespace-reserved-2.rs:52:10 | LL | #[derive(my_macro_attr)] | ^^^^^^^^^^^^^ -error: macro `my_macro_attr` may not be used for derive attributes - --> $DIR/macro-namespace-reserved-2.rs:44:10 +error: expected derive macro, found attribute macro `my_macro_attr` + --> $DIR/macro-namespace-reserved-2.rs:52:10 | LL | #[derive(my_macro_attr)] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ not a derive macro error: can't use a procedural macro from the same crate that defines it - --> $DIR/macro-namespace-reserved-2.rs:47:10 + --> $DIR/macro-namespace-reserved-2.rs:55:10 | LL | #[derive(MyTrait)] | ^^^^^^^ error[E0658]: The attribute `my_macro` is currently unknown to the compiler and may have meaning added to it in the future - --> $DIR/macro-namespace-reserved-2.rs:34:3 + --> $DIR/macro-namespace-reserved-2.rs:38:3 | LL | #[my_macro] | ^^^^^^^^ @@ -49,8 +85,20 @@ LL | #[my_macro] = note: for more information, see https://github.com/rust-lang/rust/issues/29642 = help: add #![feature(custom_attribute)] to the crate attributes to enable +error: can't use a procedural macro from the same crate that defines it + --> $DIR/macro-namespace-reserved-2.rs:39:3 + | +LL | #[crate::my_macro] + | ^^^^^^^^^^^^^^^ + +error: expected attribute, found macro `crate::my_macro` + --> $DIR/macro-namespace-reserved-2.rs:39:3 + | +LL | #[crate::my_macro] + | ^^^^^^^^^^^^^^^ not an attribute + error: cannot find derive macro `my_macro` in this scope - --> $DIR/macro-namespace-reserved-2.rs:42:10 + --> $DIR/macro-namespace-reserved-2.rs:48:10 | LL | #[derive(my_macro)] | ^^^^^^^^ @@ -62,11 +110,11 @@ LL | my_macro_attr!(); | ^^^^^^^^^^^^^ error: cannot find macro `MyTrait!` in this scope - --> $DIR/macro-namespace-reserved-2.rs:31:5 + --> $DIR/macro-namespace-reserved-2.rs:33:5 | LL | MyTrait!(); | ^^^^^^^ -error: aborting due to 11 previous errors +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.rs b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.rs index b95791f4e99d8..b5666e4ea7072 100644 --- a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.rs +++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.rs @@ -1,6 +1,6 @@ -#[derive(rustfmt::skip)] //~ ERROR macro `rustfmt::skip` may not be used for derive attributes +#[derive(rustfmt::skip)] //~ ERROR expected derive macro, found tool attribute `rustfmt::skip` struct S; fn main() { - rustfmt::skip!(); //~ ERROR `rustfmt::skip` can only be used in attributes + rustfmt::skip!(); //~ ERROR expected macro, found tool attribute `rustfmt::skip` } diff --git a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr index 8ef27a07b7f8e..6d0f826e621c5 100644 --- a/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr +++ b/src/test/ui/tool-attributes/tool-attributes-misplaced-2.stderr @@ -1,14 +1,14 @@ -error: macro `rustfmt::skip` may not be used for derive attributes +error: expected derive macro, found tool attribute `rustfmt::skip` --> $DIR/tool-attributes-misplaced-2.rs:1:10 | LL | #[derive(rustfmt::skip)] - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ not a derive macro -error: `rustfmt::skip` can only be used in attributes +error: expected macro, found tool attribute `rustfmt::skip` --> $DIR/tool-attributes-misplaced-2.rs:5:5 | LL | rustfmt::skip!(); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ not a macro error: aborting due to 2 previous errors From 8bc187d1047b3680efe2cda53dcc83f45012578b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 23:25:46 +0300 Subject: [PATCH 25/37] resolve: Include stdlib prelude into name lookup in macro namespace This is going to be used when built-in macros are defined through libcore and made available to other crates through standard library prelude --- src/librustc_resolve/macros.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 30969948c4c8c..7cb33ca3ed4c0 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -867,7 +867,7 @@ impl<'a> Resolver<'a> { } } } - WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros, + WhereToResolve::MacroUsePrelude => WhereToResolve::StdLibPrelude, WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs, WhereToResolve::BuiltinAttrs => WhereToResolve::LegacyPluginHelpers, WhereToResolve::LegacyPluginHelpers => break, // nowhere else to search @@ -877,7 +877,7 @@ impl<'a> Resolver<'a> { WhereToResolve::StdLibPrelude => match ns { TypeNS => WhereToResolve::BuiltinTypes, ValueNS => break, // nowhere else to search - MacroNS => unreachable!(), + MacroNS => WhereToResolve::BuiltinMacros, } WhereToResolve::BuiltinTypes => break, // nowhere else to search }; From f92394209455bf14594f279249c2e592809180cd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 23:59:03 +0300 Subject: [PATCH 26/37] resolve: Divide macro path resolution into speculative and error reporting parts Also move macro stability checking closer to other checks performed on obtained resolutions. Tighten the stability spans as well, it is an error to *refer* to and unstable entity in any way, not only "call" it. --- src/librustc_resolve/build_reduced_graph.rs | 6 +- src/librustc_resolve/macros.rs | 101 +++++++++--------- .../passes/collect_intra_doc_links.rs | 4 +- .../ui/feature-gates/feature-gate-asm.stderr | 2 +- .../ui/feature-gates/feature-gate-asm2.stderr | 2 +- .../feature-gate-concat_idents.stderr | 4 +- .../feature-gate-concat_idents2.stderr | 2 +- .../feature-gate-concat_idents3.stderr | 4 +- .../feature-gate-format_args_nl.stderr | 2 +- .../feature-gate-global_asm.stderr | 2 +- .../feature-gate-log_syntax.stderr | 2 +- .../feature-gate-log_syntax2.stderr | 2 +- .../feature-gate-trace_macros.stderr | 2 +- src/test/ui/macros/macro-deprecation.stderr | 4 +- src/test/ui/macros/macro-stability.stderr | 10 +- src/test/ui/rust-unstable-column-gated.stderr | 2 +- src/test/ui/trace_macros-gate.stderr | 8 +- 17 files changed, 77 insertions(+), 82 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index f74d07a3c5ee6..16fd8cccc8920 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -755,11 +755,7 @@ impl<'a> Resolver<'a> { } } - pub fn get_macro(&mut self, res: Res) -> Lrc { - self.opt_get_macro(res).expect("expected `DefKind::Macro` or `Res::NonMacroAttr`") - } - - crate fn opt_get_macro(&mut self, res: Res) -> Option> { + pub fn get_macro(&mut self, res: Res) -> Option> { let def_id = match res { Res::Def(DefKind::Macro(..), def_id) => def_id, Res::NonMacroAttr(attr_kind) => diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7cb33ca3ed4c0..077c126bdee66 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -229,13 +229,10 @@ impl<'a> base::Resolver for Resolver<'a> { }; let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - let (res, ext) = self.resolve_macro_to_res(path, kind, &parent_scope, true, force)?; + let (ext, res) = self.smart_resolve_macro_path(path, kind, &parent_scope, true, force)?; let span = invoc.span(); - let descr = fast_print_path(path); - invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, descr)); - - self.check_stability_and_deprecation(&ext, descr, span); + invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, fast_print_path(path))); if let Res::Def(_, def_id) = res { if after_derive { @@ -275,47 +272,42 @@ impl<'a> Resolver<'a> { } } - fn resolve_macro_to_res( + /// Resolve macro path with error reporting and recovery. + fn smart_resolve_macro_path( &mut self, path: &ast::Path, kind: MacroKind, parent_scope: &ParentScope<'a>, trace: bool, force: bool, - ) -> Result<(Res, Lrc), Indeterminate> { - let res = self.resolve_macro_to_res_inner(path, kind, parent_scope, trace, force); + ) -> Result<(Lrc, Res), Indeterminate> { + let (ext, res) = match self.resolve_macro_path(path, kind, parent_scope, trace, force) { + Ok((Some(ext), res)) => (ext, res), + // Use dummy syntax extensions for unresolved macros for better recovery. + Ok((None, res)) => (self.dummy_ext(kind), res), + Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err), + Err(Determinacy::Undetermined) => return Err(Indeterminate), + }; // Report errors and enforce feature gates for the resolved macro. let features = self.session.features_untracked(); - if res != Err(Determinacy::Undetermined) { - // Do not report duplicated errors on every undetermined resolution. - for segment in &path.segments { - if let Some(args) = &segment.args { - self.session.span_err(args.span(), "generic arguments in macro path"); - } - if kind == MacroKind::Attr && !features.rustc_attrs && - segment.ident.as_str().starts_with("rustc") { - let msg = "attributes starting with `rustc` are \ - reserved for use by the `rustc` compiler"; - emit_feature_err( - &self.session.parse_sess, - sym::rustc_attrs, - segment.ident.span, - GateIssue::Language, - msg, - ); - } + for segment in &path.segments { + if let Some(args) = &segment.args { + self.session.span_err(args.span(), "generic arguments in macro path"); } - } - - let res = match res { - Err(Determinacy::Undetermined) => return Err(Indeterminate), - Ok(Res::Err) | Err(Determinacy::Determined) => { - // Return dummy syntax extensions for unresolved macros for better recovery. - return Ok((Res::Err, self.dummy_ext(kind))); + if kind == MacroKind::Attr && !features.rustc_attrs && + segment.ident.as_str().starts_with("rustc") { + let msg = + "attributes starting with `rustc` are reserved for use by the `rustc` compiler"; + emit_feature_err( + &self.session.parse_sess, + sym::rustc_attrs, + segment.ident.span, + GateIssue::Language, + msg, + ); } - Ok(res) => res, - }; + } match res { Res::Def(DefKind::Macro(_), def_id) => { @@ -345,20 +337,22 @@ impl<'a> Resolver<'a> { } } } + Res::Err => {} _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), }; - let ext = self.get_macro(res); + self.check_stability_and_deprecation(&ext, path); + Ok(if ext.macro_kind() != kind { let expected = if kind == MacroKind::Attr { "attribute" } else { kind.descr() }; let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path); self.session.struct_span_err(path.span, &msg) .span_label(path.span, format!("not {} {}", kind.article(), expected)) .emit(); - // Return dummy syntax extensions for unexpected macro kinds for better recovery. - (Res::Err, self.dummy_ext(kind)) + // Use dummy syntax extensions for unexpected macro kinds for better recovery. + (self.dummy_ext(kind), Res::Err) } else { - (res, ext) + (ext, res) }) } @@ -416,14 +410,14 @@ impl<'a> Resolver<'a> { err.emit(); } - pub fn resolve_macro_to_res_inner( + pub fn resolve_macro_path( &mut self, path: &ast::Path, kind: MacroKind, parent_scope: &ParentScope<'a>, trace: bool, force: bool, - ) -> Result { + ) -> Result<(Option>, Res), Determinacy> { let path_span = path.span; let mut path = Segment::from_path(path); @@ -435,7 +429,7 @@ impl<'a> Resolver<'a> { path.insert(0, Segment::from_ident(root)); } - if path.len() > 1 { + let res = if path.len() > 1 { let res = match self.resolve_path(&path, Some(MacroNS), parent_scope, false, path_span, CrateLint::No) { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { @@ -471,7 +465,9 @@ impl<'a> Resolver<'a> { let res = binding.map(|binding| binding.res()); self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); res - } + }; + + res.map(|res| (self.get_macro(res), res)) } // Resolve an identifier in lexical scope. @@ -600,16 +596,18 @@ impl<'a> Resolver<'a> { let mut result = Err(Determinacy::Determined); for derive in &parent_scope.derives { let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope }; - match self.resolve_macro_to_res(derive, MacroKind::Derive, - &parent_scope, true, force) { - Ok((_, ext)) => if ext.helper_attrs.contains(&ident.name) { + match self.resolve_macro_path(derive, MacroKind::Derive, + &parent_scope, true, force) { + Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) { let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), ty::Visibility::Public, derive.span, Mark::root()) .to_name_binding(self.arenas); result = Ok((binding, Flags::empty())); break; } - Err(Indeterminate) => result = Err(Determinacy::Undetermined), + Ok(_) | Err(Determinacy::Determined) => {} + Err(Determinacy::Undetermined) => + result = Err(Determinacy::Undetermined), } } result @@ -1004,7 +1002,8 @@ impl<'a> Resolver<'a> { } } - fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, descr: Symbol, span: Span) { + fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &ast::Path) { + let span = path.span; if let Some(stability) = &ext.stability { if let StabilityLevel::Unstable { reason, issue } = stability.level { let feature = stability.feature; @@ -1013,14 +1012,14 @@ impl<'a> Resolver<'a> { } } if let Some(depr) = &stability.rustc_depr { - let (message, lint) = stability::rustc_deprecation_message(depr, &descr.as_str()); + let (message, lint) = stability::rustc_deprecation_message(depr, &path.to_string()); stability::early_report_deprecation( self.session, &message, depr.suggestion, lint, span ); } } if let Some(depr) = &ext.deprecation { - let (message, lint) = stability::deprecation_message(depr, &descr.as_str()); + let (message, lint) = stability::deprecation_message(depr, &path.to_string()); stability::early_report_deprecation(self.session, &message, None, lint, span); } } @@ -1101,7 +1100,7 @@ impl<'a> Resolver<'a> { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. if ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive { - let macro_kind = self.opt_get_macro(res).map(|ext| ext.macro_kind()); + let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind()); if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) { self.session.span_err( ident.span, &format!("name `{}` is reserved in attribute namespace", ident) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index acf7a951856ea..c527ed02bc05b 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -429,10 +429,10 @@ fn macro_resolve(cx: &DocContext<'_>, path_str: &str) -> Option { let segment = ast::PathSegment::from_ident(Ident::from_str(path_str)); let path = ast::Path { segments: vec![segment], span: DUMMY_SP }; cx.enter_resolver(|resolver| { - if let Ok(res @ Res::Def(DefKind::Macro(_), _)) = resolver.resolve_macro_to_res_inner( + if let Ok((Some(ext), res)) = resolver.resolve_macro_path( &path, MacroKind::Bang, &resolver.dummy_parent_scope(), false, false ) { - if let SyntaxExtensionKind::LegacyBang { .. } = resolver.get_macro(res).kind { + if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { return Some(res.map_id(|_| panic!("unexpected id"))); } } diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr index 0d7f8d819ab5e..ab5cda43bfc82 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'asm': inline assembly is not stab --> $DIR/feature-gate-asm.rs:3:9 | LL | asm!(""); - | ^^^^^^^^^ + | ^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29722 = help: add `#![feature(asm)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr index b60a34be43404..7519cad9a96ad 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'asm': inline assembly is not stab --> $DIR/feature-gate-asm2.rs:5:26 | LL | println!("{:?}", asm!("")); - | ^^^^^^^^ + | ^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29722 = help: add `#![feature(asm)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents.stderr index 4dc687451df9c..8639f622cd732 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i --> $DIR/feature-gate-concat_idents.rs:5:13 | LL | let a = concat_idents!(X, Y_1); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add `#![feature(concat_idents)]` to the crate attributes to enable @@ -11,7 +11,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i --> $DIR/feature-gate-concat_idents.rs:6:13 | LL | let b = concat_idents!(X, Y_2); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add `#![feature(concat_idents)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr index 4eb038b4a552d..4ae5e3e73087b 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents2.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i --> $DIR/feature-gate-concat_idents2.rs:4:5 | LL | concat_idents!(a, b); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add `#![feature(concat_idents)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr index e96cd4734d847..367638693d70a 100644 --- a/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr +++ b/src/test/ui/feature-gates/feature-gate-concat_idents3.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i --> $DIR/feature-gate-concat_idents3.rs:7:20 | LL | assert_eq!(10, concat_idents!(X, Y_1)); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add `#![feature(concat_idents)]` to the crate attributes to enable @@ -11,7 +11,7 @@ error[E0658]: use of unstable library feature 'concat_idents': `concat_idents` i --> $DIR/feature-gate-concat_idents3.rs:8:20 | LL | assert_eq!(20, concat_idents!(X, Y_2)); - | ^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29599 = help: add `#![feature(concat_idents)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr b/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr index b836a508f7b59..b211e2f8ed8a2 100644 --- a/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr +++ b/src/test/ui/feature-gates/feature-gate-format_args_nl.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'format_args_nl': `format_args_nl` --> $DIR/feature-gate-format_args_nl.rs:2:5 | LL | format_args_nl!(""); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: add `#![feature(format_args_nl)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-global_asm.stderr b/src/test/ui/feature-gates/feature-gate-global_asm.stderr index 416078489f173..733b8d08f77dd 100644 --- a/src/test/ui/feature-gates/feature-gate-global_asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-global_asm.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'global_asm': `global_asm!` is not --> $DIR/feature-gate-global_asm.rs:1:1 | LL | global_asm!(""); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/35119 = help: add `#![feature(global_asm)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax.stderr b/src/test/ui/feature-gates/feature-gate-log_syntax.stderr index 58f522cf82308..fa57c20ecd5d5 100644 --- a/src/test/ui/feature-gates/feature-gate-log_syntax.stderr +++ b/src/test/ui/feature-gates/feature-gate-log_syntax.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'log_syntax': `log_syntax!` is not --> $DIR/feature-gate-log_syntax.rs:2:5 | LL | log_syntax!() - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add `#![feature(log_syntax)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr index 3228b9c3013b7..0443b988b41dc 100644 --- a/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr +++ b/src/test/ui/feature-gates/feature-gate-log_syntax2.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'log_syntax': `log_syntax!` is not --> $DIR/feature-gate-log_syntax2.rs:4:22 | LL | println!("{:?}", log_syntax!()); - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add `#![feature(log_syntax)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-trace_macros.stderr b/src/test/ui/feature-gates/feature-gate-trace_macros.stderr index eb41ee45d225b..cca0818752718 100644 --- a/src/test/ui/feature-gates/feature-gate-trace_macros.stderr +++ b/src/test/ui/feature-gates/feature-gate-trace_macros.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is --> $DIR/feature-gate-trace_macros.rs:2:5 | LL | trace_macros!(true); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add `#![feature(trace_macros)]` to the crate attributes to enable diff --git a/src/test/ui/macros/macro-deprecation.stderr b/src/test/ui/macros/macro-deprecation.stderr index e5f4df5223752..4c2ad7d2fe9e7 100644 --- a/src/test/ui/macros/macro-deprecation.stderr +++ b/src/test/ui/macros/macro-deprecation.stderr @@ -2,7 +2,7 @@ warning: use of deprecated item 'local_deprecated': local deprecation note --> $DIR/macro-deprecation.rs:11:5 | LL | local_deprecated!(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: #[warn(deprecated)] on by default @@ -10,5 +10,5 @@ warning: use of deprecated item 'deprecated_macro': deprecation note --> $DIR/macro-deprecation.rs:12:5 | LL | deprecated_macro!(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/macros/macro-stability.stderr b/src/test/ui/macros/macro-stability.stderr index 6f84c450a2efb..21c48bfe5e78c 100644 --- a/src/test/ui/macros/macro-stability.stderr +++ b/src/test/ui/macros/macro-stability.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'local_unstable' --> $DIR/macro-stability.rs:19:5 | LL | local_unstable!(); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: add `#![feature(local_unstable)]` to the crate attributes to enable @@ -10,7 +10,7 @@ error[E0658]: use of unstable library feature 'local_unstable' --> $DIR/macro-stability.rs:20:5 | LL | local_unstable_modern!(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(local_unstable)]` to the crate attributes to enable @@ -18,7 +18,7 @@ error[E0658]: use of unstable library feature 'unstable_macros' --> $DIR/macro-stability.rs:21:5 | LL | unstable_macro!(); - | ^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^ | = help: add `#![feature(unstable_macros)]` to the crate attributes to enable @@ -26,7 +26,7 @@ warning: use of deprecated item 'deprecated_macro': deprecation reason --> $DIR/macro-stability.rs:24:5 | LL | deprecated_macro!(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ | = note: #[warn(deprecated)] on by default @@ -34,7 +34,7 @@ warning: use of deprecated item 'local_deprecated': local deprecation reason --> $DIR/macro-stability.rs:26:5 | LL | local_deprecated!(); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/rust-unstable-column-gated.stderr b/src/test/ui/rust-unstable-column-gated.stderr index f85122922c83e..c581a16dbb038 100644 --- a/src/test/ui/rust-unstable-column-gated.stderr +++ b/src/test/ui/rust-unstable-column-gated.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature '__rust_unstable_column': internal --> $DIR/rust-unstable-column-gated.rs:2:20 | LL | println!("{}", __rust_unstable_column!()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(__rust_unstable_column)]` to the crate attributes to enable diff --git a/src/test/ui/trace_macros-gate.stderr b/src/test/ui/trace_macros-gate.stderr index adf813c162acc..7b9542730713c 100644 --- a/src/test/ui/trace_macros-gate.stderr +++ b/src/test/ui/trace_macros-gate.stderr @@ -2,7 +2,7 @@ error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is --> $DIR/trace_macros-gate.rs:4:5 | LL | trace_macros!(); - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add `#![feature(trace_macros)]` to the crate attributes to enable @@ -17,7 +17,7 @@ error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is --> $DIR/trace_macros-gate.rs:6:5 | LL | trace_macros!(true); - | ^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add `#![feature(trace_macros)]` to the crate attributes to enable @@ -26,7 +26,7 @@ error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is --> $DIR/trace_macros-gate.rs:7:5 | LL | trace_macros!(false); - | ^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29598 = help: add `#![feature(trace_macros)]` to the crate attributes to enable @@ -35,7 +35,7 @@ error[E0658]: use of unstable library feature 'trace_macros': `trace_macros` is --> $DIR/trace_macros-gate.rs:10:26 | LL | ($x: ident) => { trace_macros!($x) } - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^ ... LL | expando!(true); | --------------- in this macro invocation From 0ec6ea7333a8918a96f40110e014f2bbbd72281f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Jul 2019 19:45:23 +0300 Subject: [PATCH 27/37] resolve: Fix access to extern and stdlib prelude from opaque macros Ok, it's hard to explain what happens, but identifier's hygienic contexts need to be "adjusted" to modules/scopes before they are resolved in them. To be resolved in all kinds on preludes the identifier needs to be adjusted to the root expansion (aka "no expansion"). Previously this was done for the `macro m() { ::my_crate::foo }` case, but forgotten for all other cases. --- src/librustc_resolve/lib.rs | 1 + src/librustc_resolve/macros.rs | 1 + .../ui/hygiene/auxiliary/stdlib-prelude.rs | 3 +++ .../stdlib-prelude-from-opaque-early.rs | 21 +++++++++++++++++++ .../stdlib-prelude-from-opaque-late.rs | 16 ++++++++++++++ 5 files changed, 42 insertions(+) create mode 100644 src/test/ui/hygiene/auxiliary/stdlib-prelude.rs create mode 100644 src/test/ui/hygiene/stdlib-prelude-from-opaque-early.rs create mode 100644 src/test/ui/hygiene/stdlib-prelude-from-opaque-late.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 795ff3faffa33..1216a083700d9 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2247,6 +2247,7 @@ impl<'a> Resolver<'a> { } if !module.no_implicit_prelude { + ident.span.adjust(Mark::root()); if ns == TypeNS { if let Some(binding) = self.extern_prelude_get(ident, !record_used) { return Some(LexicalScopeBinding::Item(binding)); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 077c126bdee66..7ad54d572f4e8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -856,6 +856,7 @@ impl<'a> Resolver<'a> { match self.hygienic_lexical_parent(module, &mut ident.span) { Some(parent_module) => WhereToResolve::Module(parent_module), None => { + ident.span.adjust(Mark::root()); use_prelude = !module.no_implicit_prelude; match ns { TypeNS => WhereToResolve::ExternPrelude, diff --git a/src/test/ui/hygiene/auxiliary/stdlib-prelude.rs b/src/test/ui/hygiene/auxiliary/stdlib-prelude.rs new file mode 100644 index 0000000000000..81b0b7faa5ba7 --- /dev/null +++ b/src/test/ui/hygiene/auxiliary/stdlib-prelude.rs @@ -0,0 +1,3 @@ +#![feature(decl_macro)] + +pub macro stdlib_macro() {} diff --git a/src/test/ui/hygiene/stdlib-prelude-from-opaque-early.rs b/src/test/ui/hygiene/stdlib-prelude-from-opaque-early.rs new file mode 100644 index 0000000000000..c8c5c72bf95c4 --- /dev/null +++ b/src/test/ui/hygiene/stdlib-prelude-from-opaque-early.rs @@ -0,0 +1,21 @@ +// check-pass +// aux-build:stdlib-prelude.rs + +#![feature(decl_macro)] +#![feature(prelude_import)] + +extern crate stdlib_prelude; + +#[prelude_import] +use stdlib_prelude::*; + +macro mac() { + mod m { + use std::mem; // OK (extern prelude) + stdlib_macro!(); // OK (stdlib prelude) + } +} + +mac!(); + +fn main() {} diff --git a/src/test/ui/hygiene/stdlib-prelude-from-opaque-late.rs b/src/test/ui/hygiene/stdlib-prelude-from-opaque-late.rs new file mode 100644 index 0000000000000..cf65de2bc2395 --- /dev/null +++ b/src/test/ui/hygiene/stdlib-prelude-from-opaque-late.rs @@ -0,0 +1,16 @@ +// check-pass + +#![feature(decl_macro)] + +macro mac() { + mod m { + fn f() { + std::mem::drop(0); // OK (extern prelude) + drop(0); // OK (stdlib prelude) + } + } +} + +mac!(); + +fn main() {} From d1949b1ab01dbd482008f64af54161cc43bb0991 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Jul 2019 20:25:34 +0300 Subject: [PATCH 28/37] expand: Do not overwrite existing `ExpnInfo` when injecting derive markers Create a fresh expansion for them instead - this is the usual way to allow unstable features for generated/desugared code. Fixes https://github.com/rust-lang/rust/issues/52363 --- src/libsyntax/ext/derive.rs | 7 ++++--- src/libsyntax_pos/hygiene.rs | 6 +++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 68e7225c3cfc5..11c1fceb7e752 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -8,7 +8,7 @@ use crate::symbol::{Symbol, sym}; use crate::errors::Applicability; use syntax_pos::Span; - +use syntax_pos::hygiene::{Mark, SyntaxContext}; use rustc_data_structures::fx::FxHashSet; pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { @@ -55,12 +55,13 @@ pub fn add_derived_markers(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P names.insert(unwrap_or!(path.segments.get(0), continue).ident.name); } - cx.current_expansion.mark.set_expn_info(ExpnInfo::with_unstable( + let mark = Mark::fresh(cx.current_expansion.mark); + mark.set_expn_info(ExpnInfo::with_unstable( ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span, cx.parse_sess.edition, &[sym::rustc_attrs, sym::structural_match], )); - let span = span.with_ctxt(cx.backtrace()); + let span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); item.visit_attrs(|attrs| { if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) { let meta = cx.meta_word(span, sym::structural_match); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 28d452233cceb..ba2b2b7a2dd11 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -117,7 +117,11 @@ impl Mark { #[inline] pub fn set_expn_info(self, info: ExpnInfo) { - HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info)) + HygieneData::with(|data| { + let old_info = &mut data.marks[self.0 as usize].expn_info; + assert!(old_info.is_none(), "expansion info is reset for a mark"); + *old_info = Some(info); + }) } pub fn is_descendant_of(self, ancestor: Mark) -> bool { From 99c7432896bbfdab1f7f70f8d763cab5f3efe64a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Jul 2019 21:02:45 +0300 Subject: [PATCH 29/37] hygiene: Introduce a helper method for creating new expansions Creating a fresh expansion and immediately generating a span from it is the most common scenario. Also avoid allocating `allow_internal_unstable` lists for derive markers repeatedly. And rename `ExpnInfo::with_unstable` to `ExpnInfo::allow_unstable`, seems to be a better fitting name. --- src/librustc/hir/lowering.rs | 8 ++-- src/librustc/ty/query/on_disk_cache.rs | 45 ++++++++++---------- src/librustc_allocator/expand.rs | 12 ++---- src/librustc_resolve/macros.rs | 7 ++- src/libsyntax/ext/base.rs | 2 + src/libsyntax/ext/derive.rs | 7 +-- src/libsyntax/ext/expand.rs | 4 +- src/libsyntax/std_inject.rs | 22 +++------- src/libsyntax/test.rs | 23 +++------- src/libsyntax_ext/proc_macro_decls.rs | 6 +-- src/libsyntax_pos/hygiene.rs | 59 +++++++++++--------------- src/libsyntax_pos/symbol.rs | 2 + 12 files changed, 80 insertions(+), 117 deletions(-) diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index c44fd30be850a..7e7bb5f61a324 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -60,7 +60,7 @@ use syntax::attr; use syntax::ast; use syntax::ast::*; use syntax::errors; -use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::ext::hygiene::Mark; use syntax::print::pprust; use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned}; use syntax::std_inject; @@ -875,13 +875,11 @@ impl<'a> LoweringContext<'a> { span: Span, allow_internal_unstable: Option>, ) -> Span { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo { + span.fresh_expansion(Mark::root(), ExpnInfo { def_site: span, allow_internal_unstable, ..ExpnInfo::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) - }); - span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) + }) } fn with_anonymous_lifetime_mode( diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 56c9474170cad..d0be13a711117 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -588,41 +588,40 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { let expn_info_tag = u8::decode(self)?; - let ctxt = match expn_info_tag { + // FIXME(mw): This method does not restore `MarkData::parent` or + // `SyntaxContextData::prev_ctxt` or `SyntaxContextData::opaque`. These things + // don't seem to be used after HIR lowering, so everything should be fine + // as long as incremental compilation does not kick in before that. + let location = || Span::new(lo, hi, SyntaxContext::empty()); + let recover_from_expn_info = |this: &Self, expn_info, pos| { + let span = location().fresh_expansion(Mark::root(), expn_info); + this.synthetic_expansion_infos.borrow_mut().insert(pos, span.ctxt()); + span + }; + Ok(match expn_info_tag { TAG_NO_EXPANSION_INFO => { - SyntaxContext::empty() + location() } TAG_EXPANSION_INFO_INLINE => { - let pos = AbsoluteBytePos::new(self.opaque.position()); - let expn_info: ExpnInfo = Decodable::decode(self)?; - let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); - ctxt + let expn_info = Decodable::decode(self)?; + recover_from_expn_info( + self, expn_info, AbsoluteBytePos::new(self.opaque.position()) + ) } TAG_EXPANSION_INFO_SHORTHAND => { let pos = AbsoluteBytePos::decode(self)?; - let cached_ctxt = self.synthetic_expansion_infos - .borrow() - .get(&pos) - .cloned(); - - if let Some(ctxt) = cached_ctxt { - ctxt + if let Some(cached_ctxt) = self.synthetic_expansion_infos.borrow().get(&pos) { + Span::new(lo, hi, *cached_ctxt) } else { - let expn_info = self.with_position(pos.to_usize(), |this| { - ExpnInfo::decode(this) - })?; - let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); - ctxt + let expn_info = + self.with_position(pos.to_usize(), |this| ExpnInfo::decode(this))?; + recover_from_expn_info(self, expn_info, pos) } } _ => { unreachable!() } - }; - - Ok(Span::new(lo, hi, ctxt)) + }) } } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index d0eefbb11799f..9803ee99f1a47 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -14,7 +14,7 @@ use syntax::{ base::{ExtCtxt, MacroKind, Resolver}, build::AstBuilder, expand::ExpansionConfig, - hygiene::{Mark, SyntaxContext}, + hygiene::Mark, }, mut_visit::{self, MutVisitor}, parse::ParseSess, @@ -84,16 +84,12 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { } self.found = true; - // Create a fresh Mark for the new macro expansion we are about to do - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo::with_unstable( + // Create a new expansion for the generated allocator code. + let span = item.span.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable( ExpnKind::Macro(MacroKind::Attr, sym::global_allocator), item.span, self.sess.edition, - &[sym::rustc_attrs], + [sym::rustc_attrs][..].into(), )); - // Tie the span to the macro expansion info we just created - let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); - // Create an expansion config let ecfg = ExpansionConfig::default(self.crate_name.take().unwrap()); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7ad54d572f4e8..6f276e04a5a39 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -17,7 +17,7 @@ use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Indeterminate}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; -use syntax::ext::hygiene::{self, Mark}; +use syntax::ext::hygiene::{self, Mark, ExpnInfo, ExpnKind}; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{feature_err, emit_feature_err, is_builtin_attr_name}; use syntax::feature_gate::{AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES}; @@ -148,7 +148,10 @@ impl<'a> base::Resolver for Resolver<'a> { } fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { - let mark = Mark::fresh(Mark::root()); + let span = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::default( + ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition() + )); + let mark = span.ctxt().outer(); let module = self.module_map[&self.definitions.local_def_id(id)]; self.definitions.set_invocation_parent(mark, module.def_id().unwrap().index); self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index cb4edee30cdbf..37d5885db60c3 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -721,6 +721,7 @@ pub struct ExtCtxt<'a> { pub resolver: &'a mut dyn Resolver, pub current_expansion: ExpansionData, pub expansions: FxHashMap>, + pub allow_derive_markers: Lrc<[Symbol]>, } impl<'a> ExtCtxt<'a> { @@ -740,6 +741,7 @@ impl<'a> ExtCtxt<'a> { directory_ownership: DirectoryOwnership::Owned { relative: None }, }, expansions: FxHashMap::default(), + allow_derive_markers: [sym::rustc_attrs, sym::structural_match][..].into(), } } diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 11c1fceb7e752..1c15deab37377 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -8,7 +8,6 @@ use crate::symbol::{Symbol, sym}; use crate::errors::Applicability; use syntax_pos::Span; -use syntax_pos::hygiene::{Mark, SyntaxContext}; use rustc_data_structures::fx::FxHashSet; pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { @@ -55,13 +54,11 @@ pub fn add_derived_markers(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P names.insert(unwrap_or!(path.segments.get(0), continue).ident.name); } - let mark = Mark::fresh(cx.current_expansion.mark); - mark.set_expn_info(ExpnInfo::with_unstable( + let span = span.fresh_expansion(cx.current_expansion.mark, ExpnInfo::allow_unstable( ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span, - cx.parse_sess.edition, &[sym::rustc_attrs, sym::structural_match], + cx.parse_sess.edition, cx.allow_derive_markers.clone(), )); - let span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); item.visit_attrs(|attrs| { if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) { let meta = cx.meta_word(span, sym::structural_match); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 2349382eb5e9b..39a8a7af2a301 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -362,7 +362,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { derives.reserve(traits.len()); invocations.reserve(traits.len()); for path in traits { - let mark = Mark::fresh(self.cx.current_expansion.mark); + let mark = Mark::fresh(self.cx.current_expansion.mark, None); derives.push(mark); invocations.push(Invocation { kind: InvocationKind::Derive { @@ -847,7 +847,7 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { - let mark = Mark::fresh(self.cx.current_expansion.mark); + let mark = Mark::fresh(self.cx.current_expansion.mark, None); self.invocations.push(Invocation { kind, fragment_kind, diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 81f9ff9b6613b..d86b76f71eca7 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -1,7 +1,7 @@ use crate::ast; use crate::attr; use crate::edition::Edition; -use crate::ext::hygiene::{Mark, SyntaxContext, MacroKind}; +use crate::ext::hygiene::{Mark, MacroKind}; use crate::symbol::{Ident, Symbol, kw, sym}; use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan}; use crate::ptr::P; @@ -9,19 +9,7 @@ use crate::tokenstream::TokenStream; use std::cell::Cell; use std::iter; -use syntax_pos::{DUMMY_SP, Span}; - -/// Craft a span that will be ignored by the stability lint's -/// call to source_map's `is_internal` check. -/// The expanded code uses the unstable `#[prelude_import]` attribute. -fn ignored_span(sp: Span, edition: Edition) -> Span { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::Macro(MacroKind::Attr, Symbol::intern("std_inject")), sp, edition, - &[sym::prelude_import], - )); - sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) -} +use syntax_pos::DUMMY_SP; pub fn injected_crate_name() -> Option<&'static str> { INJECTED_CRATE_NAME.with(|name| name.get()) @@ -87,7 +75,11 @@ pub fn maybe_inject_crates_ref( INJECTED_CRATE_NAME.with(|opt_name| opt_name.set(Some(name))); - let span = ignored_span(DUMMY_SP, edition); + let span = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable( + ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition, + [sym::prelude_import][..].into(), + )); + krate.module.items.insert(0, P(ast::Item { attrs: vec![ast::Attribute { style: ast::AttrStyle::Outer, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 7ec7bb6ff458f..799d64a996237 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -43,7 +43,6 @@ struct TestCtxt<'a> { test_cases: Vec, reexport_test_harness_main: Option, is_libtest: bool, - ctxt: SyntaxContext, features: &'a Features, test_runner: Option, @@ -259,8 +258,6 @@ fn generate_test_harness(sess: &ParseSess, let mut cleaner = EntryPointCleaner { depth: 0 }; cleaner.visit_crate(krate); - let mark = Mark::fresh(Mark::root()); - let mut econfig = ExpansionConfig::default("test".to_string()); econfig.features = Some(features); @@ -274,16 +271,10 @@ fn generate_test_harness(sess: &ParseSess, is_libtest: attr::find_crate_name(&krate.attrs) .map(|s| s == sym::test).unwrap_or(false), toplevel_reexport: None, - ctxt: SyntaxContext::empty().apply_mark(mark), features, test_runner }; - mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, sess.edition, - &[sym::main, sym::test, sym::rustc_attrs], - )); - TestHarnessGenerator { cx, tests: Vec::new(), @@ -291,13 +282,6 @@ fn generate_test_harness(sess: &ParseSess, }.visit_crate(krate); } -/// Craft a span that will be ignored by the stability lint's -/// call to source_map's `is_internal` check. -/// The expanded code calls some unstable functions in the test crate. -fn ignored_span(cx: &TestCtxt<'_>, sp: Span) -> Span { - sp.with_ctxt(cx.ctxt) -} - enum HasTestSignature { Yes, No(BadTestSignature), @@ -314,12 +298,15 @@ enum BadTestSignature { /// Creates a function item for use as the main function of a test build. /// This function will call the `test_runner` as specified by the crate attribute fn mk_main(cx: &mut TestCtxt<'_>) -> P { - // Writing this out by hand with 'ignored_span': + // Writing this out by hand: // pub fn main() { // #![main] // test::test_main_static(&[..tests]); // } - let sp = ignored_span(cx, DUMMY_SP); + let sp = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable( + ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, cx.ext_cx.parse_sess.edition, + [sym::main, sym::test, sym::rustc_attrs][..].into(), + )); let ecx = &cx.ext_cx; let test_id = Ident::with_empty_ctxt(sym::test); diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs index 0733a8ec95c71..2f78644dff2aa 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -346,12 +346,10 @@ fn mk_decls( custom_attrs: &[ProcMacroDef], custom_macros: &[ProcMacroDef], ) -> P { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo::with_unstable( + let span = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable( ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, - &[sym::rustc_attrs, Symbol::intern("proc_macro_internals")], + [sym::rustc_attrs, sym::proc_macro_internals][..].into(), )); - let span = DUMMY_SP.apply_mark(mark); let hidden = cx.meta_list_item_word(span, sym::hidden); let doc = cx.meta_list(span, sym::doc, vec![hidden]); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index ba2b2b7a2dd11..f060bf356f6d7 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -82,11 +82,8 @@ pub enum Transparency { } impl Mark { - pub fn fresh(parent: Mark) -> Self { - HygieneData::with(|data| { - data.marks.push(MarkData { parent, expn_info: None }); - Mark(data.marks.len() as u32 - 1) - }) + pub fn fresh(parent: Mark, expn_info: Option) -> Self { + HygieneData::with(|data| data.fresh_mark(parent, expn_info)) } /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST. @@ -180,6 +177,11 @@ impl HygieneData { GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut())) } + fn fresh_mark(&mut self, parent: Mark, expn_info: Option) -> Mark { + self.marks.push(MarkData { parent, expn_info }); + Mark(self.marks.len() as u32 - 1) + } + fn expn_info(&self, mark: Mark) -> Option<&ExpnInfo> { self.marks[mark.0 as usize].expn_info.as_ref() } @@ -396,33 +398,6 @@ impl SyntaxContext { SyntaxContext(raw) } - // Allocate a new SyntaxContext with the given ExpnInfo. This is used when - // deserializing Spans from the incr. comp. cache. - // FIXME(mw): This method does not restore MarkData::parent or - // SyntaxContextData::prev_ctxt or SyntaxContextData::opaque. These things - // don't seem to be used after HIR lowering, so everything should be fine - // as long as incremental compilation does not kick in before that. - pub fn allocate_directly(expansion_info: ExpnInfo) -> Self { - HygieneData::with(|data| { - data.marks.push(MarkData { - parent: Mark::root(), - expn_info: Some(expansion_info), - }); - - let mark = Mark(data.marks.len() as u32 - 1); - - data.syntax_contexts.push(SyntaxContextData { - outer_mark: mark, - transparency: Transparency::SemiTransparent, - prev_ctxt: SyntaxContext::empty(), - opaque: SyntaxContext::empty(), - opaque_and_semitransparent: SyntaxContext::empty(), - dollar_crate_name: kw::DollarCrate, - }); - SyntaxContext(data.syntax_contexts.len() as u32 - 1) - }) - } - /// Extend a syntax context with a given mark and default transparency for that mark. pub fn apply_mark(self, mark: Mark) -> SyntaxContext { HygieneData::with(|data| data.apply_mark(self, mark)) @@ -615,6 +590,20 @@ impl fmt::Debug for SyntaxContext { } } +impl Span { + /// Creates a fresh expansion with given properties. + /// Expansions are normally created by macros, but in some cases expansions are created for + /// other compiler-generated code to set per-span properties like allowed unstable features. + /// The returned span belongs to the created expansion and has the new properties, + /// but its location is inherited from the current span. + pub fn fresh_expansion(self, parent: Mark, expn_info: ExpnInfo) -> Span { + HygieneData::with(|data| { + let mark = data.fresh_mark(parent, Some(expn_info)); + self.with_ctxt(data.apply_mark(SyntaxContext::empty(), mark)) + }) + } +} + /// A subset of properties from both macro definition and macro call available through global data. /// Avoid using this if you have access to the original definition or call structures. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] @@ -669,10 +658,10 @@ impl ExpnInfo { } } - pub fn with_unstable(kind: ExpnKind, call_site: Span, edition: Edition, - allow_internal_unstable: &[Symbol]) -> ExpnInfo { + pub fn allow_unstable(kind: ExpnKind, call_site: Span, edition: Edition, + allow_internal_unstable: Lrc<[Symbol]>) -> ExpnInfo { ExpnInfo { - allow_internal_unstable: Some(allow_internal_unstable.into()), + allow_internal_unstable: Some(allow_internal_unstable), ..ExpnInfo::default(kind, call_site, edition) } } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 89fcf3b1f8f19..581fd47c4b3b5 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -508,6 +508,7 @@ symbols! { proc_macro_expr, proc_macro_gen, proc_macro_hygiene, + proc_macro_internals, proc_macro_mod, proc_macro_non_items, proc_macro_path_invoc, @@ -631,6 +632,7 @@ symbols! { static_nobundle, static_recursion, std, + std_inject, str, stringify, stmt, From dcd30a4b175364ca1ee1efdcae701a23c5ff7d0b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Jul 2019 13:02:05 +0300 Subject: [PATCH 30/37] hygiene: Fix wording of desugaring descriptions Use variant names rather than descriptions for identifying desugarings in `#[rustc_on_unimplemented]`. Both are highly unstable, but variant name is at least a single identifier. --- .../src/language-features/on-unimplemented.md | 3 ++- src/libcore/ops/try.rs | 4 ++-- src/librustc/traits/error_reporting.rs | 2 +- src/libsyntax_pos/hygiene.rs | 17 +++++++++-------- src/libsyntax_pos/lib.rs | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/doc/unstable-book/src/language-features/on-unimplemented.md b/src/doc/unstable-book/src/language-features/on-unimplemented.md index a770ab65c26f8..8db241e4b4ebf 100644 --- a/src/doc/unstable-book/src/language-features/on-unimplemented.md +++ b/src/doc/unstable-book/src/language-features/on-unimplemented.md @@ -98,7 +98,8 @@ application of these fields based on a variety of attributes when using `crate_local`) or matching against a particular method. Currently used for `try`. - `from_desugaring`: usable both as boolean (whether the flag is present) - or matching against a particular desugaring. + or matching against a particular desugaring. The desugaring is identified + with its variant name in the `DesugaringKind` enum. For example, the `Iterator` trait can be annotated in the following way: diff --git a/src/libcore/ops/try.rs b/src/libcore/ops/try.rs index 9fa2c81954ee1..76fec1020f1ef 100644 --- a/src/libcore/ops/try.rs +++ b/src/libcore/ops/try.rs @@ -8,12 +8,12 @@ #[rustc_on_unimplemented( on(all( any(from_method="from_error", from_method="from_ok"), - from_desugaring="?"), + from_desugaring="QuestionMark"), message="the `?` operator can only be used in a \ function that returns `Result` or `Option` \ (or another type that implements `{Try}`)", label="cannot use the `?` operator in a function that returns `{Self}`"), - on(all(from_method="into_result", from_desugaring="?"), + on(all(from_method="into_result", from_desugaring="QuestionMark"), message="the `?` operator can only be applied to values \ that implement `{Try}`", label="the `?` operator cannot be applied to type `{Self}`") diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a7dfbd688c14e..352d318ba7931 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -372,7 +372,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(k) = obligation.cause.span.desugaring_kind() { flags.push((sym::from_desugaring, None)); - flags.push((sym::from_desugaring, Some(k.descr().to_string()))); + flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); } let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index f060bf356f6d7..b72da042d0465 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -734,15 +734,16 @@ pub enum DesugaringKind { } impl DesugaringKind { - pub fn descr(self) -> &'static str { + /// The description wording should combine well with "desugaring of {}". + fn descr(self) -> &'static str { match self { - DesugaringKind::CondTemporary => "if and while condition", - DesugaringKind::Async => "async", - DesugaringKind::Await => "await", - DesugaringKind::QuestionMark => "?", - DesugaringKind::TryBlock => "try block", - DesugaringKind::ExistentialType => "existential type", - DesugaringKind::ForLoop => "for loop", + DesugaringKind::CondTemporary => "`if` or `while` condition", + DesugaringKind::Async => "`async` block or function", + DesugaringKind::Await => "`await` expression", + DesugaringKind::QuestionMark => "operator `?`", + DesugaringKind::TryBlock => "`try` block", + DesugaringKind::ExistentialType => "`existential type`", + DesugaringKind::ForLoop => "`for` loop", } } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 4fd27ce4f9633..9258b71518ff1 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -442,7 +442,7 @@ impl Span { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { let (pre, post) = match info.kind { - ExpnKind::Desugaring(..) => ("desugaring of `", "`"), + ExpnKind::Desugaring(..) => ("desugaring of ", ""), ExpnKind::Macro(macro_kind, _) => match macro_kind { MacroKind::Bang => ("", "!"), MacroKind::Attr => ("#[", "]"), From eac900ac87828d6a4813f0c4a870bcdb439d1175 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Jul 2019 16:45:41 +0300 Subject: [PATCH 31/37] hygiene: Make sure each `Mark` has an associated expansion info The root expansion was missing one. Expansions created for "derive containers" (see one of the next commits for the description) also didn't get expansion info. --- src/librustc/ich/impls_syntax.rs | 1 + src/librustc/lint/mod.rs | 2 +- src/libsyntax/ext/expand.rs | 14 ++++++++++++-- src/libsyntax_pos/hygiene.rs | 20 +++++++++++++++++--- src/libsyntax_pos/lib.rs | 3 ++- 5 files changed, 33 insertions(+), 7 deletions(-) diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index 69e8c35501961..e0e7988a744c6 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -408,6 +408,7 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind { + Root, Macro(kind, descr), Desugaring(kind) }); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 3c8b0041a9847..e76c24932008d 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -885,7 +885,7 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { }; match info.kind { - ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, + ExpnKind::Root | ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, ExpnKind::Desugaring(_) => true, // well, it's "external" ExpnKind::Macro(MacroKind::Bang, _) => { if info.def_site.is_dummy() { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 39a8a7af2a301..9a6252779e0c0 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -5,7 +5,7 @@ use crate::source_map::{dummy_spanned, respan}; use crate::config::StripUnconfigured; use crate::ext::base::*; use crate::ext::derive::{add_derived_markers, collect_derives}; -use crate::ext::hygiene::{Mark, SyntaxContext}; +use crate::ext::hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnKind}; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use crate::mut_visit::*; @@ -847,7 +847,17 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { - let mark = Mark::fresh(self.cx.current_expansion.mark, None); + // Expansion info for all the collected invocations is set upon their resolution, + // with exception of the "derive container" case which is not resolved and can get + // its expansion info immediately. + let expn_info = match &kind { + InvocationKind::Attr { attr: None, item, .. } => Some(ExpnInfo::default( + ExpnKind::Macro(MacroKind::Attr, sym::derive), + item.span(), self.cx.parse_sess.edition, + )), + _ => None, + }; + let mark = Mark::fresh(self.cx.current_expansion.mark, expn_info); self.invocations.push(Invocation { kind, fragment_kind, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index b72da042d0465..5df1443923090 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -59,6 +59,9 @@ pub struct Mark(u32); #[derive(Debug)] struct MarkData { parent: Mark, + /// Each mark should have an associated expansion info, but sometimes there's a delay between + /// creation of a mark and obtaining its info (e.g. macros are collected first and then + /// resolved later), so we use an `Option` here. expn_info: Option, } @@ -155,11 +158,11 @@ crate struct HygieneData { } impl HygieneData { - crate fn new() -> Self { + crate fn new(edition: Edition) -> Self { HygieneData { marks: vec![MarkData { parent: Mark::root(), - expn_info: None, + expn_info: Some(ExpnInfo::default(ExpnKind::Root, DUMMY_SP, edition)), }], syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), @@ -183,7 +186,15 @@ impl HygieneData { } fn expn_info(&self, mark: Mark) -> Option<&ExpnInfo> { - self.marks[mark.0 as usize].expn_info.as_ref() + if mark != Mark::root() { + Some(self.marks[mark.0 as usize].expn_info.as_ref() + .expect("no expansion info for a mark")) + } else { + // FIXME: Some code relies on `expn_info().is_none()` meaning "no expansion". + // Introduce a method for checking for "no expansion" instead and always return + // `ExpnInfo` from this function instead of the `Option`. + None + } } fn is_descendant_of(&self, mut mark: Mark, ancestor: Mark) -> bool { @@ -670,6 +681,8 @@ impl ExpnInfo { /// Expansion kind. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum ExpnKind { + /// No expansion, aka root expansion. Only `Mark::root()` has this kind. + Root, /// Expansion produced by a macro. /// FIXME: Some code injected by the compiler before HIR lowering also gets this kind. Macro(MacroKind, Symbol), @@ -680,6 +693,7 @@ pub enum ExpnKind { impl ExpnKind { pub fn descr(&self) -> Symbol { match *self { + ExpnKind::Root => kw::PathRoot, ExpnKind::Macro(_, descr) => descr, ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()), } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9258b71518ff1..5ccfe5f0b8b1a 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -60,7 +60,7 @@ impl Globals { Globals { symbol_interner: Lock::new(symbol::Interner::fresh()), span_interner: Lock::new(span_encoding::SpanInterner::default()), - hygiene_data: Lock::new(hygiene::HygieneData::new()), + hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), edition, } } @@ -442,6 +442,7 @@ impl Span { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { let (pre, post) = match info.kind { + ExpnKind::Root => break, ExpnKind::Desugaring(..) => ("desugaring of ", ""), ExpnKind::Macro(macro_kind, _) => match macro_kind { MacroKind::Bang => ("", "!"), From 374a80a86de4dabae4975fae04fb67cc6e6dc0bb Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Jul 2019 18:29:22 +0300 Subject: [PATCH 32/37] expand: It's always possible to create a dummy AST fragment Remove a bunch of `Option`s that assumed that dummy fragment creation could fail. The test output changed due to not performing the expansion in `fn expand_invoc` in case of the recursion limit hit. --- src/libsyntax/ext/expand.rs | 83 +++++++++---------- src/test/ui/macros/trace_faulty_macros.stderr | 2 - 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 9a6252779e0c0..85a31b8b7e853 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -158,8 +158,8 @@ ast_fragments! { } impl AstFragmentKind { - fn dummy(self, span: Span) -> Option { - self.make_from(DummyResult::any(span)) + fn dummy(self, span: Span) -> AstFragment { + self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment") } fn expect_from_annotatables>(self, items: I) @@ -327,10 +327,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { - let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); - let fragment = self.expand_invoc(invoc, &ext).unwrap_or_else(|| { - invoc_fragment_kind.dummy(invoc_span).unwrap() - }); + let fragment = self.expand_invoc(invoc, &ext); self.collect_invocations(fragment, &[]) } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { if !item.derive_allowed() { @@ -477,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option { + fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> AstFragment { if invoc.fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() { if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else { @@ -487,12 +484,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - let result = match invoc.kind { - InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext)?, - InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext)?, - InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext)?, - }; - if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { let info = self.cx.current_expansion.mark.expn_info().unwrap(); let suggested_limit = self.cx.ecfg.recursion_limit * 2; @@ -507,15 +498,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { FatalError.raise(); } - Some(result) + match invoc.kind { + InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), + InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), + InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), + } } fn expand_attr_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option { + -> AstFragment { let (attr, mut item) = match invoc.kind { - InvocationKind::Attr { attr, item, .. } => (attr?, item), + InvocationKind::Attr { attr: Some(attr), item, .. } => (attr, item), _ => unreachable!(), }; @@ -526,13 +521,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { attr::mark_used(&attr); } item.visit_attrs(|attrs| attrs.push(attr)); - Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item))) + invoc.fragment_kind.expect_from_annotatables(iter::once(item)) } SyntaxExtensionKind::LegacyAttr(expander) => { - let meta = attr.parse_meta(self.cx.parse_sess) - .map_err(|mut e| { e.emit(); }).ok()?; - let item = expander.expand(self.cx, attr.span, &meta, item); - Some(invoc.fragment_kind.expect_from_annotatables(item)) + match attr.parse_meta(self.cx.parse_sess) { + Ok(meta) => { + let item = expander.expand(self.cx, attr.span, &meta, item); + invoc.fragment_kind.expect_from_annotatables(item) + } + Err(mut err) => { + err.emit(); + invoc.fragment_kind.dummy(attr.span) + } + } } SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_attr_item(attr.span, &item); @@ -598,14 +599,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ); } - fn gate_proc_macro_expansion(&self, span: Span, fragment: &Option) { + fn gate_proc_macro_expansion(&self, span: Span, fragment: &AstFragment) { if self.cx.ecfg.proc_macro_hygiene() { return } - let fragment = match fragment { - Some(fragment) => fragment, - None => return, - }; fragment.visit_with(&mut DisallowMacros { span, @@ -641,7 +638,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_bang_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option { + -> AstFragment { let kind = invoc.fragment_kind; let (mac, span) = match invoc.kind { InvocationKind::Bang { mac, span } => (mac, span), @@ -649,7 +646,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let path = &mac.node.path; - let opt_expanded = match &ext.kind { + match &ext.kind { SyntaxExtensionKind::Bang(expander) => { self.gate_proc_macro_expansion_kind(span, kind); let tok_result = expander.expand(self.cx, span, mac.node.stream()); @@ -659,19 +656,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } SyntaxExtensionKind::LegacyBang(expander) => { let tok_result = expander.expand(self.cx, span, mac.node.stream()); - kind.make_from(tok_result) + if let Some(result) = kind.make_from(tok_result) { + result + } else { + let msg = format!("non-{kind} macro in {kind} position: {name}", + name = path.segments[0].ident.name, kind = kind.name()); + self.cx.span_err(path.span, &msg); + self.cx.trace_macros_diag(); + kind.dummy(span) + } } _ => unreachable!() - }; - - if opt_expanded.is_some() { - opt_expanded - } else { - let msg = format!("non-{kind} macro in {kind} position: {name}", - name = path.segments[0].ident.name, kind = kind.name()); - self.cx.span_err(path.span, &msg); - self.cx.trace_macros_diag(); - kind.dummy(span) } } @@ -703,7 +698,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_derive_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option { + -> AstFragment { let (path, item) = match invoc.kind { InvocationKind::Derive { path, item, item_with_markers } => match ext.kind { SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers), @@ -712,7 +707,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; if !item.derive_allowed() { - return None; + return invoc.fragment_kind.dummy(path.span); } match &ext.kind { @@ -721,7 +716,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span: path.span, path }; let span = meta.span.with_ctxt(self.cx.backtrace()); let items = expander.expand(self.cx, span, &meta, item); - Some(invoc.fragment_kind.expect_from_annotatables(items)) + invoc.fragment_kind.expect_from_annotatables(items) } _ => unreachable!() } @@ -732,12 +727,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind: AstFragmentKind, path: &Path, span: Span) - -> Option { + -> AstFragment { let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::>()); match parser.parse_ast_fragment(kind, false) { Ok(fragment) => { parser.ensure_complete_parse(path, kind.name(), span); - Some(fragment) + fragment } Err(mut err) => { err.set_span(span); diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index 233d3dcfcb6db..fc05012377b2a 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -45,8 +45,6 @@ LL | my_recursive_macro!(); = note: to `my_recursive_macro ! ( ) ;` = note: expanding `my_recursive_macro! { }` = note: to `my_recursive_macro ! ( ) ;` - = note: expanding `my_recursive_macro! { }` - = note: to `my_recursive_macro ! ( ) ;` error: aborting due to 2 previous errors From b003dd6d9badf0e66b6e90af2052fefef94d4a43 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Jul 2019 18:55:29 +0300 Subject: [PATCH 33/37] expand: Merge `expand_{bang,attr,derive}_invoc` into a single function It's more convenient to have all this highly related stuff together on one screen (for future refactorings). The `expand_invoc` function is compact enough now, after all the previous refactorings. --- src/libsyntax/ext/expand.rs | 194 +++++++++++--------------- src/test/ui/macros/macro-error.stderr | 2 +- 2 files changed, 79 insertions(+), 117 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 85a31b8b7e853..f1235e7174f2c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -327,7 +327,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { - let fragment = self.expand_invoc(invoc, &ext); + let fragment = self.expand_invoc(invoc, &ext.kind); self.collect_invocations(fragment, &[]) } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { if !item.derive_allowed() { @@ -474,12 +474,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> AstFragment { - if invoc.fragment_kind == AstFragmentKind::ForeignItems && - !self.cx.ecfg.macros_in_extern() { - if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else { + fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment { + let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); + if fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() { + if let SyntaxExtensionKind::NonMacroAttr { .. } = ext {} else { emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern, - invoc.span(), GateIssue::Language, + span, GateIssue::Language, "macro invocations in `extern {}` blocks are experimental"); } } @@ -499,58 +499,84 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } match invoc.kind { - InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), - InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), - InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), - } - } - - fn expand_attr_invoc(&mut self, - invoc: Invocation, - ext: &SyntaxExtension) - -> AstFragment { - let (attr, mut item) = match invoc.kind { - InvocationKind::Attr { attr: Some(attr), item, .. } => (attr, item), - _ => unreachable!(), - }; - - match &ext.kind { - SyntaxExtensionKind::NonMacroAttr { mark_used } => { - attr::mark_known(&attr); - if *mark_used { - attr::mark_used(&attr); + InvocationKind::Bang { mac, .. } => match ext { + SyntaxExtensionKind::Bang(expander) => { + self.gate_proc_macro_expansion_kind(span, fragment_kind); + let tok_result = expander.expand(self.cx, span, mac.node.stream()); + let result = + self.parse_ast_fragment(tok_result, fragment_kind, &mac.node.path, span); + self.gate_proc_macro_expansion(span, &result); + result + } + SyntaxExtensionKind::LegacyBang(expander) => { + let tok_result = expander.expand(self.cx, span, mac.node.stream()); + if let Some(result) = fragment_kind.make_from(tok_result) { + result + } else { + let msg = format!("non-{kind} macro in {kind} position: {path}", + kind = fragment_kind.name(), path = mac.node.path); + self.cx.span_err(span, &msg); + self.cx.trace_macros_diag(); + fragment_kind.dummy(span) + } } - item.visit_attrs(|attrs| attrs.push(attr)); - invoc.fragment_kind.expect_from_annotatables(iter::once(item)) + _ => unreachable!() } - SyntaxExtensionKind::LegacyAttr(expander) => { - match attr.parse_meta(self.cx.parse_sess) { - Ok(meta) => { - let item = expander.expand(self.cx, attr.span, &meta, item); - invoc.fragment_kind.expect_from_annotatables(item) + InvocationKind::Attr { attr: Some(attr), mut item, .. } => match ext { + SyntaxExtensionKind::Attr(expander) => { + self.gate_proc_macro_attr_item(span, &item); + let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item { + Annotatable::Item(item) => token::NtItem(item), + Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()), + Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()), + Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()), + Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), + Annotatable::Expr(expr) => token::NtExpr(expr), + })), DUMMY_SP).into(); + let input = self.extract_proc_macro_attr_input(attr.tokens, span); + let tok_result = expander.expand(self.cx, span, input, item_tok); + let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span); + self.gate_proc_macro_expansion(span, &res); + res + } + SyntaxExtensionKind::LegacyAttr(expander) => { + match attr.parse_meta(self.cx.parse_sess) { + Ok(meta) => { + let item = expander.expand(self.cx, span, &meta, item); + fragment_kind.expect_from_annotatables(item) + } + Err(mut err) => { + err.emit(); + fragment_kind.dummy(span) + } } - Err(mut err) => { - err.emit(); - invoc.fragment_kind.dummy(attr.span) + } + SyntaxExtensionKind::NonMacroAttr { mark_used } => { + attr::mark_known(&attr); + if *mark_used { + attr::mark_used(&attr); } + item.visit_attrs(|attrs| attrs.push(attr)); + fragment_kind.expect_from_annotatables(iter::once(item)) } + _ => unreachable!() } - SyntaxExtensionKind::Attr(expander) => { - self.gate_proc_macro_attr_item(attr.span, &item); - let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item { - Annotatable::Item(item) => token::NtItem(item), - Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()), - Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()), - Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()), - Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), - Annotatable::Expr(expr) => token::NtExpr(expr), - })), DUMMY_SP).into(); - let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span); - let tok_result = expander.expand(self.cx, attr.span, input, item_tok); - let res = self.parse_ast_fragment(tok_result, invoc.fragment_kind, - &attr.path, attr.span); - self.gate_proc_macro_expansion(attr.span, &res); - res + InvocationKind::Derive { path, item, item_with_markers } => match ext { + SyntaxExtensionKind::Derive(expander) | + SyntaxExtensionKind::LegacyDerive(expander) => { + let (path, item) = match ext { + SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers), + _ => (path, item), + }; + if !item.derive_allowed() { + return fragment_kind.dummy(span); + } + let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span, path }; + let span = span.with_ctxt(self.cx.backtrace()); + let items = expander.expand(self.cx, span, &meta, item); + fragment_kind.expect_from_annotatables(items) + } + _ => unreachable!() } _ => unreachable!() } @@ -634,42 +660,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - /// Expand a macro invocation. Returns the resulting expanded AST fragment. - fn expand_bang_invoc(&mut self, - invoc: Invocation, - ext: &SyntaxExtension) - -> AstFragment { - let kind = invoc.fragment_kind; - let (mac, span) = match invoc.kind { - InvocationKind::Bang { mac, span } => (mac, span), - _ => unreachable!(), - }; - let path = &mac.node.path; - - match &ext.kind { - SyntaxExtensionKind::Bang(expander) => { - self.gate_proc_macro_expansion_kind(span, kind); - let tok_result = expander.expand(self.cx, span, mac.node.stream()); - let result = self.parse_ast_fragment(tok_result, kind, path, span); - self.gate_proc_macro_expansion(span, &result); - result - } - SyntaxExtensionKind::LegacyBang(expander) => { - let tok_result = expander.expand(self.cx, span, mac.node.stream()); - if let Some(result) = kind.make_from(tok_result) { - result - } else { - let msg = format!("non-{kind} macro in {kind} position: {name}", - name = path.segments[0].ident.name, kind = kind.name()); - self.cx.span_err(path.span, &msg); - self.cx.trace_macros_diag(); - kind.dummy(span) - } - } - _ => unreachable!() - } - } - fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) { let kind = match kind { AstFragmentKind::Expr => "expressions", @@ -694,34 +684,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ); } - /// Expand a derive invocation. Returns the resulting expanded AST fragment. - fn expand_derive_invoc(&mut self, - invoc: Invocation, - ext: &SyntaxExtension) - -> AstFragment { - let (path, item) = match invoc.kind { - InvocationKind::Derive { path, item, item_with_markers } => match ext.kind { - SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers), - _ => (path, item), - } - _ => unreachable!(), - }; - if !item.derive_allowed() { - return invoc.fragment_kind.dummy(path.span); - } - - match &ext.kind { - SyntaxExtensionKind::Derive(expander) | - SyntaxExtensionKind::LegacyDerive(expander) => { - let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span: path.span, path }; - let span = meta.span.with_ctxt(self.cx.backtrace()); - let items = expander.expand(self.cx, span, &meta, item); - invoc.fragment_kind.expect_from_annotatables(items) - } - _ => unreachable!() - } - } - fn parse_ast_fragment(&mut self, toks: TokenStream, kind: AstFragmentKind, diff --git a/src/test/ui/macros/macro-error.stderr b/src/test/ui/macros/macro-error.stderr index b3aed8c2cef24..2539a6d51561c 100644 --- a/src/test/ui/macros/macro-error.stderr +++ b/src/test/ui/macros/macro-error.stderr @@ -8,7 +8,7 @@ error: non-type macro in type position: cfg --> $DIR/macro-error.rs:8:12 | LL | let _: cfg!(foo) = (); - | ^^^ + | ^^^^^^^^^ error: aborting due to 2 previous errors From baddce5155f7358af319818b10c992790dc8c572 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 8 Jul 2019 01:00:43 +0300 Subject: [PATCH 34/37] expand: Move "derive containers" into a separate `InvocationKind` variant `InvocationKind::Attr { attr: None, .. }` meaning something entirely different from a regular attribute was confusing as hell. --- src/librustc_resolve/macros.rs | 8 +++---- src/libsyntax/ext/expand.rs | 39 ++++++++++++++++++++++------------ 2 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 6f276e04a5a39..fc1becfe30960 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -221,14 +221,14 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) -> Result>, Indeterminate> { let (path, kind, derives_in_scope, after_derive) = match invoc.kind { - InvocationKind::Attr { attr: None, .. } => - return Ok(None), - InvocationKind::Attr { attr: Some(ref attr), ref traits, after_derive, .. } => - (&attr.path, MacroKind::Attr, traits.clone(), after_derive), + InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => + (&attr.path, MacroKind::Attr, derives.clone(), after_derive), InvocationKind::Bang { ref mac, .. } => (&mac.node.path, MacroKind::Bang, Vec::new(), false), InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, Vec::new(), false), + InvocationKind::DeriveContainer { .. } => + return Ok(None), }; let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f1235e7174f2c..7fc62e357c5c4 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -199,9 +199,10 @@ pub enum InvocationKind { span: Span, }, Attr { - attr: Option, - traits: Vec, + attr: ast::Attribute, item: Annotatable, + // Required for resolving derive helper attributes. + derives: Vec, // We temporarily report errors for attribute macros placed after derives after_derive: bool, }, @@ -210,15 +211,22 @@ pub enum InvocationKind { item: Annotatable, item_with_markers: Annotatable, }, + /// "Invocation" that contains all derives from an item, + /// broken into multiple `Derive` invocations when expanded. + /// FIXME: Find a way to remove it. + DeriveContainer { + derives: Vec, + item: Annotatable, + }, } impl Invocation { pub fn span(&self) -> Span { - match self.kind { - InvocationKind::Bang { span, .. } => span, - InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span, - InvocationKind::Attr { attr: None, .. } => DUMMY_SP, - InvocationKind::Derive { ref path, .. } => path.span, + match &self.kind { + InvocationKind::Bang { span, .. } => *span, + InvocationKind::Attr { attr, .. } => attr.span, + InvocationKind::Derive { path, .. } => path.span, + InvocationKind::DeriveContainer { item, .. } => item.span(), } } } @@ -329,7 +337,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let (expanded_fragment, new_invocations) = if let Some(ext) = ext { let fragment = self.expand_invoc(invoc, &ext.kind); self.collect_invocations(fragment, &[]) - } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { + } else if let InvocationKind::DeriveContainer { derives: traits, item } = invoc.kind { if !item.derive_allowed() { let attr = attr::find_by_name(item.attrs(), sym::derive) .expect("`derive` attribute should exist"); @@ -522,7 +530,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => unreachable!() } - InvocationKind::Attr { attr: Some(attr), mut item, .. } => match ext { + InvocationKind::Attr { attr, mut item, .. } => match ext { SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_attr_item(span, &item); let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item { @@ -578,7 +586,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => unreachable!() } - _ => unreachable!() + InvocationKind::DeriveContainer { .. } => unreachable!() } } @@ -805,10 +813,10 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { // Expansion info for all the collected invocations is set upon their resolution, - // with exception of the "derive container" case which is not resolved and can get + // with exception of the derive container case which is not resolved and can get // its expansion info immediately. let expn_info = match &kind { - InvocationKind::Attr { attr: None, item, .. } => Some(ExpnInfo::default( + InvocationKind::DeriveContainer { item, .. } => Some(ExpnInfo::default( ExpnKind::Macro(MacroKind::Attr, sym::derive), item.span(), self.cx.parse_sess.edition, )), @@ -833,12 +841,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_attr(&mut self, attr: Option, - traits: Vec, + derives: Vec, item: Annotatable, kind: AstFragmentKind, after_derive: bool) -> AstFragment { - self.collect(kind, InvocationKind::Attr { attr, traits, item, after_derive }) + self.collect(kind, match attr { + Some(attr) => InvocationKind::Attr { attr, item, derives, after_derive }, + None => InvocationKind::DeriveContainer { derives, item }, + }) } fn find_attr_invoc(&self, attrs: &mut Vec, after_derive: &mut bool) From 7b74d72d9a4414f088d7f638343d5d8a7c67084a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 8 Jul 2019 01:00:54 +0300 Subject: [PATCH 35/37] Fix failing tests --- src/librustc/ty/query/on_disk_cache.rs | 5 +++-- .../feature-gates/feature-gate-custom_test_frameworks.stderr | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index d0be13a711117..a508d9846bce3 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -610,8 +610,9 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { } TAG_EXPANSION_INFO_SHORTHAND => { let pos = AbsoluteBytePos::decode(self)?; - if let Some(cached_ctxt) = self.synthetic_expansion_infos.borrow().get(&pos) { - Span::new(lo, hi, *cached_ctxt) + let cached_ctxt = self.synthetic_expansion_infos.borrow().get(&pos).cloned(); + if let Some(ctxt) = cached_ctxt { + Span::new(lo, hi, ctxt) } else { let expn_info = self.with_position(pos.to_usize(), |this| ExpnInfo::decode(this))?; diff --git a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr index 1cc53db2c364c..38304e7f3f934 100644 --- a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr +++ b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr @@ -1,8 +1,8 @@ error[E0658]: use of unstable library feature 'custom_test_frameworks': custom test frameworks are an unstable feature - --> $DIR/feature-gate-custom_test_frameworks.rs:3:1 + --> $DIR/feature-gate-custom_test_frameworks.rs:3:3 | LL | #[test_case] - | ^^^^^^^^^^^^ + | ^^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/50297 = help: add `#![feature(custom_test_frameworks)]` to the crate attributes to enable From e86e5cb38ffb9a55f6d9ab6ebda2d384fb154626 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 8 Jul 2019 21:58:42 +0300 Subject: [PATCH 36/37] Add a regression test for #44692 Add a test for the issue resolved by removing `resolve_macro_path` Add a test making sure that extern prelude entries introduced from an opaque macro are not visible anywhere, even it that macro Fix test output after rebase --- .../derives/auxiliary/derive-marker-tricky.rs | 15 ++++++++ src/test/ui/derives/derive-marker-tricky.rs | 16 ++++++++ .../extern-prelude-from-opaque-fail.rs | 28 ++++++++++++++ .../extern-prelude-from-opaque-fail.stderr | 37 +++++++++++++++++++ .../macros/derive-in-eager-expansion-hang.rs | 14 +++++++ .../derive-in-eager-expansion-hang.stderr | 17 +++++++++ .../macro-namespace-reserved-2.stderr | 2 +- 7 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/derives/auxiliary/derive-marker-tricky.rs create mode 100644 src/test/ui/derives/derive-marker-tricky.rs create mode 100644 src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs create mode 100644 src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr create mode 100644 src/test/ui/macros/derive-in-eager-expansion-hang.rs create mode 100644 src/test/ui/macros/derive-in-eager-expansion-hang.stderr diff --git a/src/test/ui/derives/auxiliary/derive-marker-tricky.rs b/src/test/ui/derives/auxiliary/derive-marker-tricky.rs new file mode 100644 index 0000000000000..70345351bd09d --- /dev/null +++ b/src/test/ui/derives/auxiliary/derive-marker-tricky.rs @@ -0,0 +1,15 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::*; + +#[proc_macro_derive(NoMarker)] +pub fn f(input: TokenStream) -> TokenStream { + if input.to_string().contains("rustc_copy_clone_marker") { + panic!("found `#[rustc_copy_clone_marker]`"); + } + TokenStream::new() +} diff --git a/src/test/ui/derives/derive-marker-tricky.rs b/src/test/ui/derives/derive-marker-tricky.rs new file mode 100644 index 0000000000000..730ea4714c789 --- /dev/null +++ b/src/test/ui/derives/derive-marker-tricky.rs @@ -0,0 +1,16 @@ +// Test that `#[rustc_copy_clone_marker]` is not injected when a user-defined derive shadows +// a built-in derive in non-trivial scope (e.g. in a nested module). + +// check-pass +// aux-build:derive-marker-tricky.rs + +extern crate derive_marker_tricky; + +mod m { + use derive_marker_tricky::NoMarker as Copy; + + #[derive(Copy)] + struct S; +} + +fn main() {} diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs new file mode 100644 index 0000000000000..06d62656e957f --- /dev/null +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs @@ -0,0 +1,28 @@ +#![feature(decl_macro)] + +macro a() { + extern crate core as my_core; + mod v { + // Early resolution. + use my_core; //~ ERROR unresolved import `my_core` + } + mod u { + // Late resolution. + fn f() { my_core::mem::drop(0); } + //~^ ERROR failed to resolve: use of undeclared type or module `my_core` + } +} + +a!(); + +mod v { + // Early resolution. + use my_core; //~ ERROR unresolved import `my_core` +} +mod u { + // Late resolution. + fn f() { my_core::mem::drop(0); } + //~^ ERROR failed to resolve: use of undeclared type or module `my_core` +} + +fn main() {} diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr new file mode 100644 index 0000000000000..65133eb1e1873 --- /dev/null +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr @@ -0,0 +1,37 @@ +error[E0432]: unresolved import `my_core` + --> $DIR/extern-prelude-from-opaque-fail.rs:20:9 + | +LL | use my_core; + | ^^^^^^^ + | | + | no `my_core` in the root + | help: a similar name exists in the module: `my_core` + +error[E0432]: unresolved import `my_core` + --> $DIR/extern-prelude-from-opaque-fail.rs:7:13 + | +LL | use my_core; + | ^^^^^^^ no `my_core` in the root +... +LL | a!(); + | ----- in this macro invocation + +error[E0433]: failed to resolve: use of undeclared type or module `my_core` + --> $DIR/extern-prelude-from-opaque-fail.rs:11:18 + | +LL | fn f() { my_core::mem::drop(0); } + | ^^^^^^^ use of undeclared type or module `my_core` +... +LL | a!(); + | ----- in this macro invocation + +error[E0433]: failed to resolve: use of undeclared type or module `my_core` + --> $DIR/extern-prelude-from-opaque-fail.rs:24:14 + | +LL | fn f() { my_core::mem::drop(0); } + | ^^^^^^^ use of undeclared type or module `my_core` + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/macros/derive-in-eager-expansion-hang.rs b/src/test/ui/macros/derive-in-eager-expansion-hang.rs new file mode 100644 index 0000000000000..0729e14d5b273 --- /dev/null +++ b/src/test/ui/macros/derive-in-eager-expansion-hang.rs @@ -0,0 +1,14 @@ +// Regression test for the issue #44692 + +macro_rules! hang { () => { + { //~ ERROR format argument must be a string literal + #[derive(Clone)] + struct S; + + "" + } +}} + +fn main() { + format_args!(hang!()); +} diff --git a/src/test/ui/macros/derive-in-eager-expansion-hang.stderr b/src/test/ui/macros/derive-in-eager-expansion-hang.stderr new file mode 100644 index 0000000000000..1ef9427666bc5 --- /dev/null +++ b/src/test/ui/macros/derive-in-eager-expansion-hang.stderr @@ -0,0 +1,17 @@ +error: format argument must be a string literal + --> $DIR/derive-in-eager-expansion-hang.rs:4:5 + | +LL | / { +LL | | #[derive(Clone)] +LL | | struct S; +LL | | +LL | | "" +LL | | } + | |_____^ +help: you might be missing a string literal to format with + | +LL | format_args!("{}", hang!()); + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr index a724d388f4891..8a5e346c2b59f 100644 --- a/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr +++ b/src/test/ui/proc-macro/macro-namespace-reserved-2.stderr @@ -83,7 +83,7 @@ LL | #[my_macro] | ^^^^^^^^ | = note: for more information, see https://github.com/rust-lang/rust/issues/29642 - = help: add #![feature(custom_attribute)] to the crate attributes to enable + = help: add `#![feature(custom_attribute)]` to the crate attributes to enable error: can't use a procedural macro from the same crate that defines it --> $DIR/macro-namespace-reserved-2.rs:39:3 From 29e7bfd0c74362e89197807655b17ede1ae321c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 19 Apr 2019 18:49:15 +0200 Subject: [PATCH 37/37] Refactor diagnostic emission for green nodes --- src/librustc/dep_graph/graph.rs | 86 +++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index b8c6c1e372382..7eea336cbbfa1 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -7,6 +7,7 @@ use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, Ordering}; use std::env; use std::hash::Hash; use std::collections::hash_map::Entry; +use std::mem; use crate::ty::{self, TyCtxt}; use crate::util::common::{ProfileQueriesMsg, profq_msg}; use parking_lot::{Mutex, Condvar}; @@ -61,11 +62,11 @@ struct DepGraphData { colors: DepNodeColorMap, - /// A set of loaded diagnostics that have been emitted. - emitted_diagnostics: Mutex>, + /// A set of loaded diagnostics that is in the progress of being emitted. + emitting_diagnostics: Mutex>, /// Used to wait for diagnostics to be emitted. - emitted_diagnostics_cond_var: Condvar, + emitting_diagnostics_cond_var: Condvar, /// When we load, there may be `.o` files, cached MIR, or other such /// things available to us. If we find that they are not dirty, we @@ -99,8 +100,8 @@ impl DepGraph { previous_work_products: prev_work_products, dep_node_debug: Default::default(), current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)), - emitted_diagnostics: Default::default(), - emitted_diagnostics_cond_var: Condvar::new(), + emitting_diagnostics: Default::default(), + emitting_diagnostics_cond_var: Condvar::new(), previous: prev_graph, colors: DepNodeColorMap::new(prev_graph_node_count), loaded_from_cache: Default::default(), @@ -744,7 +745,7 @@ impl DepGraph { // There may be multiple threads trying to mark the same dep node green concurrently - let (dep_node_index, did_allocation) = { + let dep_node_index = { let mut current = data.current.borrow_mut(); // Copy the fingerprint from the previous graph, @@ -758,34 +759,36 @@ impl DepGraph { // ... emitting any stored diagnostic ... + // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere + // Maybe store a list on disk and encode this fact in the DepNodeState let diagnostics = tcx.queries.on_disk_cache - .load_diagnostics(tcx, prev_dep_node_index); + .load_diagnostics(tcx, prev_dep_node_index); + + #[cfg(not(parallel_compiler))] + debug_assert!(data.colors.get(prev_dep_node_index).is_none(), + "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \ + insertion for {:?}", dep_node); if unlikely!(diagnostics.len() > 0) { self.emit_diagnostics( tcx, data, dep_node_index, - did_allocation, + prev_dep_node_index, diagnostics ); } // ... and finally storing a "Green" entry in the color map. // Multiple threads can all write the same color here - #[cfg(not(parallel_compiler))] - debug_assert!(data.colors.get(prev_dep_node_index).is_none(), - "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \ - insertion for {:?}", dep_node); - data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node); Some(dep_node_index) } - /// Atomically emits some loaded diagnotics, assuming that this only gets called with - /// `did_allocation` set to `true` on a single thread. + /// Atomically emits some loaded diagnostics. + /// This may be called concurrently on multiple threads for the same dep node. #[cold] #[inline(never)] fn emit_diagnostics<'tcx>( @@ -793,36 +796,49 @@ impl DepGraph { tcx: TyCtxt<'tcx>, data: &DepGraphData, dep_node_index: DepNodeIndex, - did_allocation: bool, + prev_dep_node_index: SerializedDepNodeIndex, diagnostics: Vec, ) { - if did_allocation || !cfg!(parallel_compiler) { - // Only the thread which did the allocation emits the error messages - let handle = tcx.sess.diagnostic(); + let mut emitting = data.emitting_diagnostics.lock(); + + if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) { + // The node is already green so diagnostics must have been emitted already + return; + } + + if emitting.insert(dep_node_index) { + // We were the first to insert the node in the set so this thread + // must emit the diagnostics and signal other potentially waiting + // threads after. + mem::drop(emitting); // Promote the previous diagnostics to the current session. tcx.queries.on_disk_cache - .store_diagnostics(dep_node_index, diagnostics.clone().into()); + .store_diagnostics(dep_node_index, diagnostics.clone().into()); + + let handle = tcx.sess.diagnostic(); for diagnostic in diagnostics { DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); } - #[cfg(parallel_compiler)] - { - // Mark the diagnostics and emitted and wake up waiters - data.emitted_diagnostics.lock().insert(dep_node_index); - data.emitted_diagnostics_cond_var.notify_all(); - } + // Mark the node as green now that diagnostics are emitted + data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); + + // Remove the node from the set + data.emitting_diagnostics.lock().remove(&dep_node_index); + + // Wake up waiters + data.emitting_diagnostics_cond_var.notify_all(); } else { - // The other threads will wait for the diagnostics to be emitted + // We must wait for the other thread to finish emitting the diagnostic - let mut emitted_diagnostics = data.emitted_diagnostics.lock(); loop { - if emitted_diagnostics.contains(&dep_node_index) { + data.emitting_diagnostics_cond_var.wait(&mut emitting); + if data.colors + .get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) { break; } - data.emitted_diagnostics_cond_var.wait(&mut emitted_diagnostics); } } } @@ -1027,7 +1043,7 @@ impl CurrentDepGraph { hash: self.anon_id_seed.combine(hasher.finish()), }; - self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO).0 + self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO) } fn alloc_node( @@ -1037,7 +1053,7 @@ impl CurrentDepGraph { fingerprint: Fingerprint ) -> DepNodeIndex { debug_assert!(!self.node_to_node_index.contains_key(&dep_node)); - self.intern_node(dep_node, edges, fingerprint).0 + self.intern_node(dep_node, edges, fingerprint) } fn intern_node( @@ -1045,11 +1061,11 @@ impl CurrentDepGraph { dep_node: DepNode, edges: SmallVec<[DepNodeIndex; 8]>, fingerprint: Fingerprint - ) -> (DepNodeIndex, bool) { + ) -> DepNodeIndex { debug_assert_eq!(self.node_to_node_index.len(), self.data.len()); match self.node_to_node_index.entry(dep_node) { - Entry::Occupied(entry) => (*entry.get(), false), + Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { let dep_node_index = DepNodeIndex::new(self.data.len()); self.data.push(DepNodeData { @@ -1058,7 +1074,7 @@ impl CurrentDepGraph { fingerprint }); entry.insert(dep_node_index); - (dep_node_index, true) + dep_node_index } } }