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 0e782bef39dd..f972d13f7c39 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 @@ fn compare(&self, other: &[u8]) -> Ordering { #[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 f972d13f7c39..ea4ea956e59a 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 7396918196c0..e4dfd4d829e6 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 5ebb18b999ab..ad0b49fa4a21 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 c21886f26f46..000000000000 --- 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 ee77053fd5b6..a7da058de308 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 139be7fe0132..8d24ffe7a7c8 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 e4dfd4d829e6..c6b2ed13b0a8 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 67430e5bbda4..513e22a788cd 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -705,7 +705,8 @@ 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 8d24ffe7a7c8..d0d4eb032fcb 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 6d23963e141a..0cecdd7ffa0b 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -175,6 +175,7 @@ pub fn get_cloexec(&self) -> io::Result { 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 @@ pub fn set_cloexec(&self) -> io::Result<()> { 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 000000000000..9a4f87728224 --- /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 000000000000..5c865d76851d --- /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 000000000000..321b83c3459d --- /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 1db18d302825..c09b2003f386 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -89,7 +89,6 @@ fn to_stable_hash_key(&self, Bang, Attr, Derive, - ProcMacroStub, }); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 49116f3f171e..974487ab9d2d 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -29,7 +29,7 @@ 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 @@ 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 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_scope: ParentScop // 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 @@ pub fn get_macro(&mut self, res: Res) -> Lrc { 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 8f23c9813f7d..a3e00bcb81a9 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 @@ fn resolve_macro_to_res( 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 350bcc9dbc64..72e6614dc065 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 5f1a1b31616c..9affc08141d0 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -92,7 +92,6 @@ fn from(item: &'a clean::Item) -> 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 2d69c29dfae3..5c6847b41413 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2471,7 +2471,6 @@ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 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 bb85fe898dab..acf7a951856e 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 fa5faaf3ff56..009d681ed835 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -406,11 +406,8 @@ pub fn visit_item(&mut self, item: &'tcx hir::Item, // 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 c0ba41b8af40..8d5e4a3369e7 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 @@ pub fn descr(self) -> &'static str { 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 1e396f1be0e0..4bd0b092b55a 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 8d5e4a3369e7..09ff44115b49 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -24,6 +24,7 @@ use std::rc::Rc; use std::default::Default; +pub use syntax_pos::hygiene::MacroKind; #[derive(Debug,Clone)] pub enum Annotatable { @@ -518,34 +519,6 @@ fn make_ty(self: Box) -> Option> { } } -/// 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 f52952ca4027..6a2aba17a793 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -723,6 +723,34 @@ pub fn name(&self) -> Symbol { } } +/// 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 2a9fd58f84b3..549c34d961aa 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -62,8 +62,7 @@ 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 @@ fn diagnostic(&self) -> &errors::Handler { /// 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 @@ fn mark_span_with_reason( 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 @@ fn make_async_expr( }; let unstable_span = self.mark_span_with_reason( - CompilerDesugaringKind::Async, + DesugaringKind::Async, span, self.allow_gen_future.clone(), ); @@ -1733,7 +1732,7 @@ fn lower_existential_impl_trait( // 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 @@ fn lower_async_fn_ret_ty( let span = output.span(); let exist_ty_span = self.mark_span_with_reason( - CompilerDesugaringKind::Async, + DesugaringKind::Async, span, None, ); @@ -3275,7 +3274,7 @@ fn lower_maybe_async_body( }; 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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { _ => { // 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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { // 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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { 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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { 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 @@ fn lower_expr(&mut self, e: &Expr) -> hir::Expr { // } 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 @@ fn lower_await( } } 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 c09b2003f386..f679a65c642f 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -398,7 +398,7 @@ fn hash_stable(&self, impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { call_site, - format, + kind, def_site, default_transparency, allow_internal_unstable, @@ -407,13 +407,13 @@ fn hash_stable(&self, 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 4426b5c0e85b..770d5155777b 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::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 @@ pub fn need_type_info_err( )); } 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 348997369496..0b514f5927d3 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -247,10 +247,10 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { } 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 59b08b832d27..2bf4f1d3cfbb 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -35,7 +35,7 @@ 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 59a032d53cfd..ff868bf2a2ad 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -928,7 +928,7 @@ pub fn is_ref_for_guard(&self) -> bool { /// `__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 d6cc68bcdab4..fb7ed1474450 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,7 +36,7 @@ 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 @@ struct ErrorDescriptor<'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 @@ fn on_unimplemented_note( 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 d402b0ddf6e8..18bbb2571288 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -8,7 +8,7 @@ }, 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 34db080ef663..9a581cb03ecd 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -33,7 +33,7 @@ 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 @@ pub fn report_use_of_moved_value(&self, }, 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 f23cffeda689..7b5fce4abbc4 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::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 @@ pub(super) fn report_use_of_moved_or_uninitialized( 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 25ac93cc2422..31a9766af303 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 effd69dc61dd..fab2537f9d8f 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -37,7 +37,6 @@ 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 @@ pub fn get_macro_use_data(&self, span: Span) -> Option { 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 @@ pub fn get_macro_use_data(&self, span: Span) -> Option { 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 d24f92a6fafe..de42a6a35c89 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -15,7 +15,7 @@ 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 @@ pub fn check_pat_walk( // 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 4acba6d38fa2..d32ee67f7458 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -119,7 +119,7 @@ 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 @@ fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { // 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 09ff44115b49..0c986574cece 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -15,7 +15,7 @@ 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 @@ pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> 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 @@ pub fn expansion_cause(&self) -> Option { 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 2a56f3dd7566..24050be792b9 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 053686b8b1f2..879069c1418e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -506,7 +506,7 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option 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 c717f140ca36..35a1a552a13f 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -15,7 +15,7 @@ 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 45e65288a24e..dee8f4b3eb53 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -4,7 +4,7 @@ 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 24d3055e7114..7f4f1fd7e019 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -9,7 +9,7 @@ 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 186673c142f1..5f88e2e098a2 100644 --- a/src/libsyntax_ext/test_case.rs +++ b/src/libsyntax_ext/test_case.rs @@ -16,7 +16,7 @@ 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 6a2aba17a793..f36a4d5816e5 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -162,7 +162,7 @@ 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 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 @@ pub fn default(format: ExpnFormat, call_site: Span, edition: Edition) -> ExpnInf } } - 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 @@ pub fn article(self) -> &'static str { /// 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 07b9f6093202..d4c1958f7e26 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -27,7 +27,7 @@ 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 @@ pub fn allows_unstable(&self, feature: Symbol) -> bool { } /// 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 @@ pub fn is_compiler_desugaring(&self, kind: CompilerDesugaringKind) -> bool { /// 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 @@ pub fn macro_backtrace(mut self) -> Vec { 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 | 22 +++++++++++++++------- src/libsyntax_ext/test.rs | 14 +++----------- src/libsyntax_ext/test_case.rs | 14 ++------------ 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 2e999a0682b4..293a2dd94922 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 62530f4fe7b3..da0f8ca6da09 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 @@ macro_rules! register_unstable { 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 - )); + 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 + ) + }); - // format_args uses `unstable` things internally. 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 7f4f1fd7e019..c5c5ef57b312 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 5f88e2e098a2..af2cf42e04bb 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 f36a4d5816e5..f8318f54320e 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -31,7 +31,7 @@ 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 @@ pub fn outer_is_descendant_of(self, ctxt: SyntaxContext) -> bool { 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 a3e00bcb81a9..61300e3ee3ce 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -242,13 +242,6 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force 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 0c986574cece..267046655ffd 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -680,9 +680,6 @@ fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFra 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 879069c1418e..bb7d7352e055 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 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { 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 @@ fn expand_derive_invoc(&mut self, 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 549c34d961aa..c44fd30be850 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -877,7 +877,7 @@ fn mark_span_with_reason( ) -> 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 2bf4f1d3cfbb..9876d6c1fa59 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 fb7ed1474450..a7dfbd688c14 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -61,12 +61,9 @@ struct ErrorDescriptor<'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 83a0fb486fd9..361b5cd93571 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -723,39 +723,37 @@ fn fix_multispan_in_std_macros(&mut self, 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 fab2537f9d8f..aeaee1887b95 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -841,7 +841,6 @@ pub fn get_macro_use_data(&self, span: Span) -> Option { 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 @@ pub fn get_macro_use_data(&self, span: Span) -> Option { .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 @@ pub fn get_macro_use_data(&self, span: Span) -> Option { }); } - 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 267046655ffd..2f8d6f00ba79 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -219,7 +219,6 @@ fn expand<'cx>( ecx: &'cx mut ExtCtxt<'_>, span: Span, input: TokenStream, - def_span: Option, ) -> Box; } @@ -236,7 +235,6 @@ fn expand<'cx>( ecx: &'cx mut ExtCtxt<'_>, span: Span, input: TokenStream, - _def_span: Option, ) -> Box { struct AvoidInterpolatedIdents; @@ -654,7 +652,7 @@ pub fn expn_info(&self, call_site: Span, descr: &str) -> ExpnInfo { 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 bb7d7352e055..06ff2bc655cf 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -673,7 +673,7 @@ fn expand_bang_invoc(&mut self, 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 665c794422d4..5c6438a7ef53 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -88,6 +88,7 @@ pub fn make(mut self: Box>, kind: AstFragmentKind) -> AstFrag struct MacroRulesMacroExpander { name: ast::Ident, + span: Span, lhses: Vec, rhses: Vec, valid: bool, @@ -99,12 +100,11 @@ fn expand<'cx>( 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 767ab74355e6..ec0222d90eb7 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 @@ fn from_span_full(span: Span, 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 f8318f54320e..63b692ccdcb9 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 @@ pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> 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 d4c1958f7e26..1369fca3b4a5 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 7cbfef52b4aa..36cee82893a0 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 63b692ccdcb9..67dcdabe7016 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -36,10 +36,10 @@ 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } /// 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 @@ pub fn with_unstable(kind: ExpnKind, call_site: Span, edition: Edition, } /// 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 @@ pub fn article(self) -> &'static str { } /// 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 f679a65c642f..69e8c3550196 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -408,8 +408,7 @@ fn hash_stable(&self, }); 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 9876d6c1fa59..3c8b0041a984 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -38,6 +38,7 @@ 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 18bbb2571288..d0eefbb11799 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -11,7 +11,7 @@ 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 61300e3ee3ce..7f57b0a5052a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -114,17 +114,21 @@ enum SubNS { Bang, AttrLike } // We don't want to format a path using pretty-printing, // `format!("{}", path)`, because that tries to insert // line-breaks and is slow. -fn fast_print_path(path: &ast::Path) -> 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 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force }; 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 @@ pub fn finalize_current_module_macro_resolutions(&mut self) { } } - 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 @@ fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &str, spa } } 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 aeaee1887b95..2c8f7a44f5a2 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -843,7 +843,8 @@ pub fn get_macro_use_data(&self, span: Span) -> Option { 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 2f8d6f00ba79..04f124685cbb 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -640,18 +640,10 @@ pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> 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 24050be792b9..68e7225c3cfc 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 7ee073117e96..81f9ff9b6613 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 @@ 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 35a1a552a13f..7ec7bb6ff458 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -21,7 +21,7 @@ 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 dee8f4b3eb53..0733a8ec95c7 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -5,7 +5,7 @@ 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 67dcdabe7016..28d452233cce 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -135,11 +135,9 @@ pub fn outer_is_descendant_of(self, ctxt: SyntaxContext) -> bool { 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 @@ fn is_descendant_of(&self, mut mark: Mark, ancestor: Mark) -> bool { } 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -/// 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 @@ pub fn with_unstable(kind: ExpnKind, call_site: Span, edition: Edition, } } -/// 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 @@ pub fn descr(self) -> Symbol { 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 1369fca3b4a5..4fd27ce4f963 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -27,7 +27,7 @@ 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 @@ pub fn macro_backtrace(mut self) -> Vec { // 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 41073773e9f9..f946ca2903ac 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 @@ fn visit_async_fn( } 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 9e7898e10b01..9188a78e489e 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 @@ pub fn create_root_def(&mut self, 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 @@ pub fn parent_module_of_macro_def(&self, mark: Mark) -> DefId { 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 63f60d0ab952..f9092196ab3c 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 974487ab9d2d..8515029193e9 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 207b0b3754ac..09d7d8ace6bc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -19,7 +19,7 @@ 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 @@ pub fn new(session: &'a Session, 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 7f57b0a5052a..8361bbe45c48 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,7 +8,7 @@ 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 @@ 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 @@ fn next_node_id(&mut self) -> ast::NodeId { 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 @@ fn resolve_dollar_crates(&mut self) { 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 @@ pub fn dummy_parent_scope(&self) -> ParentScope<'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 @@ struct Flags: u8 { 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 @@ fn suggest_macro_name(&mut self, name: Symbol, kind: MacroKind, } } - 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 f946ca2903ac..6b93bd96a271 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -11,13 +11,13 @@ /// 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 @@ fn create_def(&mut self, 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 @@ fn visit_async_fn( } 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 @@ fn visit_anon_const(&mut self, constant: &'a AnonConst) { } 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 8515029193e9..6fdd0c3ff3e4 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -46,20 +46,6 @@ 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 @@ fn build_reduced_graph_for_item(&mut self, item: &Item, parent_scope: ParentScop // 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 09d7d8ace6bc..b6c26b1a721e 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -40,7 +40,7 @@ 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 @@ pub fn new(session: &'a Session, 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 @@ pub fn new(session: &'a Session, 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 @@ pub fn new(session: &'a Session, 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 @@ fn non_macro_attr(&self, mark_used: bool) -> Lrc { 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 8361bbe45c48..20eb97c15ba7 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -11,7 +11,7 @@ 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 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force 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 @@ fn resolve_macro_to_res( 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 @@ pub fn define_macro(&mut self, 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 @@ pub fn define_macro(&mut self, } 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 @@ pub fn define_macro(&mut self, 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 04f124685cbb..82386b78f1dc 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -10,7 +10,7 @@ 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 @@ pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> 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 583640aa8171..c7b092830a24 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 548f9e3051dd..83c77513ec3b 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 | 113 +++++++++--------- .../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, 109 insertions(+), 124 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6fdd0c3ff3e4..f74d07a3c5ee 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -9,7 +9,7 @@ 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::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 @@ fn build_reduced_graph_for_use_tree( 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 b6c26b1a721e..795ff3faffa3 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::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 20eb97c15ba7..905b3347a547 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 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 @@ fn resolve_imports(&mut self) { } 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 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force }; 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 @@ fn resolve_macro_to_res( 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 @@ fn resolve_macro_to_res( } } - 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 @@ fn resolve_macro_to_res( } } 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 @@ struct Flags: u8 { 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 7de1cd29a9ca..5edfe923e68a 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -2,6 +2,7 @@ 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::{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 82386b78f1dc..cb4edee30cdb 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -676,6 +676,9 @@ pub fn expn_info(&self, call_site: Span, descr: Symbol) -> ExpnInfo { 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 @@ fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFra 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 06ff2bc655cf..2f7fb79a7f53 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -313,9 +313,8 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { 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 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { 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 + ); } - - 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!() + 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 { - 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 283427b9acef..44f0f2d7ec03 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 f08445e1f775..fdd7bf3235c1 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 56b908d94cc8..b95791f4e99d 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 c5f5f59c32c3..8ef27a07b7f8 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 905b3347a547..30969948c4c8 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -348,7 +348,18 @@ fn resolve_macro_to_res( _ => 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 2f7fb79a7f53..2349382eb5e9 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -323,12 +323,12 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { 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 @@ fn expand_attr_invoc(&mut self, 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 @@ fn expand_bang_invoc(&mut self, 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 @@ fn expand_derive_invoc(&mut self, 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 d3a2e486416a..9ce2fb58ab0a 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 f098635c7028..7c5aa5381e8c 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 44f0f2d7ec03..0f93fcdaa5f5 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 fdd7bf3235c1..dfd6818b6785 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 c7b092830a24..7a9e472c6c3e 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 83c77513ec3b..a724d388f489 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 b95791f4e99d..b5666e4ea707 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 8ef27a07b7f8..6d0f826e621c 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 30969948c4c8..7cb33ca3ed4c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -867,7 +867,7 @@ struct Flags: u8 { } } } - 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 @@ struct Flags: u8 { 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 f74d07a3c5ee..16fd8cccc892 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -755,11 +755,7 @@ pub fn macro_def_scope(&mut self, expansion: Mark) -> Module<'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 7cb33ca3ed4c..077c126bdee6 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -229,13 +229,10 @@ fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force }; 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,48 +272,43 @@ fn invoc_parent_scope(&self, invoc_id: Mark, derives: Vec) -> ParentS } } - 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"); + } + 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, + ); } } - 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) => { if let Some(node_id) = self.definitions.as_local_node_id(def_id) { @@ -345,20 +337,22 @@ fn resolve_macro_to_res( } } } + 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 @@ fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: S 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 @@ pub fn resolve_macro_to_res_inner( 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 @@ pub fn resolve_macro_to_res_inner( 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 @@ struct Flags: u8 { 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 @@ pub fn finalize_current_module_macro_resolutions(&mut self) { } } - 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 @@ fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, descr: Symbol, } } 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 @@ fn suggest_macro_name(&mut self, name: Symbol, kind: MacroKind, // 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 acf7a951856e..c527ed02bc05 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 0d7f8d819ab5..ab5cda43bfc8 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 b60a34be4340..7519cad9a96a 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 4dc687451df9..8639f622cd73 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 4eb038b4a552..4ae5e3e73087 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 e96cd4734d84..367638693d70 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 b836a508f7b5..b211e2f8ed8a 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 416078489f17..733b8d08f77d 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 58f522cf8230..fa57c20ecd5d 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 3228b9c3013b..0443b988b41d 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 eb41ee45d225..cca081875271 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 e5f4df522375..4c2ad7d2fe9e 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 6f84c450a2ef..21c48bfe5e78 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 f85122922c83..c581a16dbb03 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 adf813c162ac..7b9542730713 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 795ff3faffa3..1216a083700d 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2247,6 +2247,7 @@ fn resolve_ident_in_lexical_scope(&mut self, } 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 077c126bdee6..7ad54d572f4e 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -856,6 +856,7 @@ struct Flags: u8 { 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 000000000000..81b0b7faa5ba --- /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 000000000000..c8c5c72bf95c --- /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 000000000000..cf65de2bc239 --- /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 68e7225c3cfc..11c1fceb7e75 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -8,7 +8,7 @@ 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 28d452233cce..ba2b2b7a2dd1 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -117,7 +117,11 @@ pub fn expn_info(self) -> Option { #[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 c44fd30be850..7e7bb5f61a32 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -60,7 +60,7 @@ 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 @@ fn mark_span_with_reason( 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 56c9474170ca..d0be13a71111 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -588,41 +588,40 @@ fn specialized_decode(&mut self) -> Result { 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 d0eefbb11799..9803ee99f1a4 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -14,7 +14,7 @@ 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 7ad54d572f4e..6f276e04a5a3 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -17,7 +17,7 @@ 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 @@ fn next_node_id(&mut self) -> ast::NodeId { } 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 cb4edee30cdb..37d5885db60c 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 @@ pub fn new(parse_sess: &'a parse::ParseSess, 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 11c1fceb7e75..1c15deab3737 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -8,7 +8,6 @@ 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 2349382eb5e9..39a8a7af2a30 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -362,7 +362,7 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { 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 81f9ff9b6613..d86b76f71eca 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 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 7ec7bb6ff458..799d64a99623 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 0733a8ec95c7..2f78644dff2a 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 ba2b2b7a2dd1..f060bf356f6d 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 @@ fn with T>(f: F) -> T { 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 @@ pub const fn empty() -> Self { 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } +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 @@ pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> 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 89fcf3b1f8f1..581fd47c4b3b 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -508,6 +508,7 @@ 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 @@ 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 a770ab65c26f..8db241e4b4eb 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 9fa2c81954ee..76fec1020f1e 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 a7dfbd688c14..352d318ba793 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -372,7 +372,7 @@ fn on_unimplemented_note( 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 f060bf356f6d..b72da042d046 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 4fd27ce4f963..9258b71518ff 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -442,7 +442,7 @@ pub fn macro_backtrace(mut self) -> Vec { // 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 69e8c3550196..e0e7988a744c 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -408,6 +408,7 @@ fn hash_stable(&self, }); 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 3c8b0041a984..e76c24932008 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 39a8a7af2a30..9a6252779e0c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -5,7 +5,7 @@ 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 b72da042d046..5df144392309 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -59,6 +59,9 @@ struct SyntaxContextData { #[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 @@ pub fn looks_like_proc_macro_derive(self) -> bool { } 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 @@ fn fresh_mark(&mut self, parent: Mark, expn_info: Option) -> Mark { } 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 @@ pub fn allow_unstable(kind: ExpnKind, call_site: Span, edition: Edition, /// 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 9258b71518ff..5ccfe5f0b8b1 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -60,7 +60,7 @@ pub fn new(edition: Edition) -> 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 @@ pub fn macro_backtrace(mut self) -> Vec { // 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 9a6252779e0c..85a31b8b7e85 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -158,8 +158,8 @@ impl<'a> MacResult for crate::ext::tt::macro_rules::ParserAnyMacro<'a> { } 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 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { // 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 @@ fn fully_configure(&mut self, item: Annotatable) -> Annotatable { } } - 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 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option 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 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option 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 @@ fn expand_attr_invoc(&mut self, 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 @@ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { ); } - 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 @@ fn visit_mac(&mut self, _mac: &'ast ast::Mac) { 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 @@ fn expand_bang_invoc(&mut self, }; 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 @@ fn expand_bang_invoc(&mut self, } 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 @@ fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) { 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 @@ fn expand_derive_invoc(&mut self, _ => unreachable!(), }; if !item.derive_allowed() { - return None; + return invoc.fragment_kind.dummy(path.span); } match &ext.kind { @@ -721,7 +716,7 @@ fn expand_derive_invoc(&mut self, 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 @@ fn parse_ast_fragment(&mut self, 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 233d3dcfcb6d..fc05012377b2 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 | 198 +++++++++++--------------- src/test/ui/macros/macro-error.stderr | 2 +- 2 files changed, 81 insertions(+), 119 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 85a31b8b7e85..f1235e7174f2 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -327,7 +327,7 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { // 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 @@ fn fully_configure(&mut self, item: Annotatable) -> Annotatable { } } - 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 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> AstFragm } 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 } - item.visit_attrs(|attrs| attrs.push(attr)); - invoc.fragment_kind.expect_from_annotatables(iter::once(item)) - } - 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) - } - Err(mut err) => { - err.emit(); - invoc.fragment_kind.dummy(attr.span) + 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) } } + _ => 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::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) + } + } + } + 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!() + } + 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 @@ fn visit_mac(&mut self, _mac: &'ast ast::Mac) { } } - /// 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 @@ fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) { ); } - /// 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 b3aed8c2cef2..2539a6d51561 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 6f276e04a5a3..fc1becfe3096 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -221,14 +221,14 @@ fn resolve_imports(&mut self) { 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 f1235e7174f2..7fc62e357c5c 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 @@ fn expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragment { 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 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstF } _ => 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 @@ fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstF } _ => 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 @@ fn collect_bang(&mut self, mac: ast::Mac, span: Span, kind: AstFragmentKind) -> 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 d0be13a71111..a508d9846bce 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -610,8 +610,9 @@ fn specialized_decode(&mut self) -> Result { } 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 1cc53db2c364..38304e7f3f93 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 000000000000..70345351bd09 --- /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 000000000000..730ea4714c78 --- /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 000000000000..06d62656e957 --- /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 000000000000..65133eb1e187 --- /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 000000000000..0729e14d5b27 --- /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 000000000000..1ef9427666bc --- /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 a724d388f489..8a5e346c2b59 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 | 88 +++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index b8c6c1e37238..7eea336cbbfa 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -7,6 +7,7 @@ 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 @@ pub fn new(prev_graph: PreviousDepGraph, 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 @@ fn try_mark_previous_green<'tcx>( // 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 @@ fn try_mark_previous_green<'tcx>( // ... 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 @@ fn emit_diagnostics<'tcx>( 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(); - } - } else { - // The other threads will wait for the diagnostics to be emitted + // 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 { + // 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 @@ fn complete_anon_task(&mut self, kind: DepKind, task_deps: TaskDeps) -> DepNodeI 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 @@ fn alloc_node( 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 @@ fn intern_node( 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 @@ fn intern_node( fingerprint }); entry.insert(dep_node_index); - (dep_node_index, true) + dep_node_index } } }