From 30b27f350ccca8f2b08b54b256f7e1fdb8c8ddb0 Mon Sep 17 00:00:00 2001 From: Andrew Champion Date: Sat, 8 Jun 2019 16:26:34 +0100 Subject: 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 0e782bef39d..f972d13f7c3 100644 --- a/src/libcore/slice/mod.rs +++ b/src/libcore/slice/mod.rs @@ -5304,6 +5304,29 @@ impl SlicePartialEq for [A] } } +// Use an equal-pointer optimization when types are `Eq` +impl SlicePartialEq for [A] + where A: PartialEq + Eq +{ + default fn equal(&self, other: &[A]) -> bool { + if self.len() != other.len() { + return false; + } + + if self.as_ptr() == other.as_ptr() { + return true; + } + + for i in 0..self.len() { + if !self[i].eq(&other[i]) { + return false; + } + } + + true + } +} + // Use memcmp for bytewise equality when the types allow impl SlicePartialEq for [A] where A: PartialEq + BytewiseEquality @@ -5409,7 +5432,7 @@ impl SliceOrd for [u8] { #[doc(hidden)] /// Trait implemented for types that can be compared for equality using /// their bytewise representation -trait BytewiseEquality { } +trait BytewiseEquality: Eq + Copy { } macro_rules! impl_marker_for { ($traitname:ident, $($ty:ty)*) => { -- cgit 1.4.1-3-g733a5 From d482589f292abda9a5c2895adf63189168f92a70 Mon Sep 17 00:00:00 2001 From: Andrew Champion Date: Sat, 8 Jun 2019 20:16:50 +0100 Subject: 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 f972d13f7c3..ea4ea956e59 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) } } -- cgit 1.4.1-3-g733a5 From 45dda939ab558b244d9099798047ec6e6376cff1 Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Mon, 1 Jul 2019 22:18:45 +0800 Subject: Move async-await tests from run-pass to ui --- src/test/run-pass/async-await/async-fn-size.rs | 106 ------------------------ src/test/run-pass/async-await/issue-60709.rs | 28 ------- src/test/ui/async-await/async-fn-size.rs | 107 +++++++++++++++++++++++++ src/test/ui/async-await/issue-60709.rs | 30 +++++++ 4 files changed, 137 insertions(+), 134 deletions(-) delete mode 100644 src/test/run-pass/async-await/async-fn-size.rs delete mode 100644 src/test/run-pass/async-await/issue-60709.rs create mode 100644 src/test/ui/async-await/async-fn-size.rs create mode 100644 src/test/ui/async-await/issue-60709.rs diff --git a/src/test/run-pass/async-await/async-fn-size.rs b/src/test/run-pass/async-await/async-fn-size.rs deleted file mode 100644 index 7396918196c..00000000000 --- a/src/test/run-pass/async-await/async-fn-size.rs +++ /dev/null @@ -1,106 +0,0 @@ -// edition:2018 - -#![feature(async_await)] - -#[path = "../auxiliary/arc_wake.rs"] -mod arc_wake; - -use std::pin::Pin; -use std::future::Future; -use std::sync::{ - Arc, - atomic::{self, AtomicUsize}, -}; -use std::task::{Context, Poll}; -use arc_wake::ArcWake; - -struct Counter { - wakes: AtomicUsize, -} - -impl ArcWake for Counter { - fn wake(self: Arc) { - Self::wake_by_ref(&self) - } - fn wake_by_ref(arc_self: &Arc) { - arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); - } -} - -struct WakeOnceThenComplete(bool, u8); - -impl Future for WakeOnceThenComplete { - type Output = u8; - fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - if self.0 { - Poll::Ready(self.1) - } else { - cx.waker().wake_by_ref(); - self.0 = true; - Poll::Pending - } - } -} - -fn wait(fut: impl Future) -> u8 { - let mut fut = Box::pin(fut); - let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); - let waker = ArcWake::into_waker(counter.clone()); - let mut cx = Context::from_waker(&waker); - loop { - match fut.as_mut().poll(&mut cx) { - Poll::Ready(out) => return out, - Poll::Pending => (), - } - } -} - -fn base() -> WakeOnceThenComplete { WakeOnceThenComplete(false, 1) } - -async fn await1_level1() -> u8 { - base().await -} - -async fn await2_level1() -> u8 { - base().await + base().await -} - -async fn await3_level1() -> u8 { - base().await + base().await + base().await -} - -async fn await3_level2() -> u8 { - await3_level1().await + await3_level1().await + await3_level1().await -} - -async fn await3_level3() -> u8 { - await3_level2().await + await3_level2().await + await3_level2().await -} - -async fn await3_level4() -> u8 { - await3_level3().await + await3_level3().await + await3_level3().await -} - -async fn await3_level5() -> u8 { - await3_level4().await + await3_level4().await + await3_level4().await -} - -fn main() { - assert_eq!(2, std::mem::size_of_val(&base())); - assert_eq!(8, std::mem::size_of_val(&await1_level1())); - assert_eq!(12, std::mem::size_of_val(&await2_level1())); - assert_eq!(12, std::mem::size_of_val(&await3_level1())); - assert_eq!(20, std::mem::size_of_val(&await3_level2())); - assert_eq!(28, std::mem::size_of_val(&await3_level3())); - assert_eq!(36, std::mem::size_of_val(&await3_level4())); - assert_eq!(44, std::mem::size_of_val(&await3_level5())); - - assert_eq!(1, wait(base())); - assert_eq!(1, wait(await1_level1())); - assert_eq!(2, wait(await2_level1())); - assert_eq!(3, wait(await3_level1())); - assert_eq!(9, wait(await3_level2())); - assert_eq!(27, wait(await3_level3())); - assert_eq!(81, wait(await3_level4())); - assert_eq!(243, wait(await3_level5())); -} diff --git a/src/test/run-pass/async-await/issue-60709.rs b/src/test/run-pass/async-await/issue-60709.rs deleted file mode 100644 index 5ebb18b999a..00000000000 --- a/src/test/run-pass/async-await/issue-60709.rs +++ /dev/null @@ -1,28 +0,0 @@ -// This used to compile the future down to ud2, due to uninhabited types being -// handled incorrectly in generators. -// compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018 - -#![feature(async_await)] -#![allow(unused)] - -use std::future::Future; -use std::task::Poll; -use std::task::Context; -use std::pin::Pin; -use std::rc::Rc; - -struct Never(); -impl Future for Never { - type Output = (); - fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { - Poll::Pending - } -} - -fn main() { - let fut = async { - let _rc = Rc::new(()); // Also crashes with Arc - Never().await; - }; - let _bla = fut; // Moving the future is required. -} diff --git a/src/test/ui/async-await/async-fn-size.rs b/src/test/ui/async-await/async-fn-size.rs new file mode 100644 index 00000000000..e4dfd4d829e --- /dev/null +++ b/src/test/ui/async-await/async-fn-size.rs @@ -0,0 +1,107 @@ +// run-pass + +// edition:2018 + +#![feature(async_await)] + +extern crate arc_wake; + +use std::pin::Pin; +use std::future::Future; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{Context, Poll}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct WakeOnceThenComplete(bool, u8); + +impl Future for WakeOnceThenComplete { + type Output = u8; + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + if self.0 { + Poll::Ready(self.1) + } else { + cx.waker().wake_by_ref(); + self.0 = true; + Poll::Pending + } + } +} + +fn wait(fut: impl Future) -> u8 { + let mut fut = Box::pin(fut); + let counter = Arc::new(Counter { wakes: AtomicUsize::new(0) }); + let waker = ArcWake::into_waker(counter.clone()); + let mut cx = Context::from_waker(&waker); + loop { + match fut.as_mut().poll(&mut cx) { + Poll::Ready(out) => return out, + Poll::Pending => (), + } + } +} + +fn base() -> WakeOnceThenComplete { WakeOnceThenComplete(false, 1) } + +async fn await1_level1() -> u8 { + base().await +} + +async fn await2_level1() -> u8 { + base().await + base().await +} + +async fn await3_level1() -> u8 { + base().await + base().await + base().await +} + +async fn await3_level2() -> u8 { + await3_level1().await + await3_level1().await + await3_level1().await +} + +async fn await3_level3() -> u8 { + await3_level2().await + await3_level2().await + await3_level2().await +} + +async fn await3_level4() -> u8 { + await3_level3().await + await3_level3().await + await3_level3().await +} + +async fn await3_level5() -> u8 { + await3_level4().await + await3_level4().await + await3_level4().await +} + +fn main() { + assert_eq!(2, std::mem::size_of_val(&base())); + assert_eq!(8, std::mem::size_of_val(&await1_level1())); + assert_eq!(12, std::mem::size_of_val(&await2_level1())); + assert_eq!(12, std::mem::size_of_val(&await3_level1())); + assert_eq!(20, std::mem::size_of_val(&await3_level2())); + assert_eq!(28, std::mem::size_of_val(&await3_level3())); + assert_eq!(36, std::mem::size_of_val(&await3_level4())); + assert_eq!(44, std::mem::size_of_val(&await3_level5())); + + assert_eq!(1, wait(base())); + assert_eq!(1, wait(await1_level1())); + assert_eq!(2, wait(await2_level1())); + assert_eq!(3, wait(await3_level1())); + assert_eq!(9, wait(await3_level2())); + assert_eq!(27, wait(await3_level3())); + assert_eq!(81, wait(await3_level4())); + assert_eq!(243, wait(await3_level5())); +} diff --git a/src/test/ui/async-await/issue-60709.rs b/src/test/ui/async-await/issue-60709.rs new file mode 100644 index 00000000000..ad0b49fa4a2 --- /dev/null +++ b/src/test/ui/async-await/issue-60709.rs @@ -0,0 +1,30 @@ +// This used to compile the future down to ud2, due to uninhabited types being +// handled incorrectly in generators. +// compile-flags: -Copt-level=z -Cdebuginfo=2 --edition=2018 + +// run-pass + +#![feature(async_await)] +#![allow(unused)] + +use std::future::Future; +use std::task::Poll; +use std::task::Context; +use std::pin::Pin; +use std::rc::Rc; + +struct Never(); +impl Future for Never { + type Output = (); + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + Poll::Pending + } +} + +fn main() { + let fut = async { + let _rc = Rc::new(()); // Also crashes with Arc + Never().await; + }; + let _bla = fut; // Moving the future is required. +} -- cgit 1.4.1-3-g733a5 From b14a2ec400aa58a71a8e69a05f8bb41f3b571c2b Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Wed, 3 Jul 2019 22:37:33 +0800 Subject: 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 --------------------------------- src/test/run-pass/futures-api.rs | 59 ------------------------------ src/test/ui/async-await/futures-api.rs | 61 +++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 123 deletions(-) delete mode 100644 src/test/run-pass/auxiliary/arc_wake.rs delete mode 100644 src/test/run-pass/futures-api.rs create mode 100644 src/test/ui/async-await/futures-api.rs 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 c21886f26f4..00000000000 --- 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/run-pass/futures-api.rs deleted file mode 100644 index ee77053fd5b..00000000000 --- a/src/test/run-pass/futures-api.rs +++ /dev/null @@ -1,59 +0,0 @@ -// aux-build:arc_wake.rs - -extern crate arc_wake; - -use std::future::Future; -use std::pin::Pin; -use std::sync::{ - Arc, - atomic::{self, AtomicUsize}, -}; -use std::task::{ - Context, Poll, -}; -use arc_wake::ArcWake; - -struct Counter { - wakes: AtomicUsize, -} - -impl ArcWake for Counter { - fn wake(self: Arc) { - Self::wake_by_ref(&self) - } - fn wake_by_ref(arc_self: &Arc) { - arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); - } -} - -struct MyFuture; - -impl Future for MyFuture { - type Output = (); - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // Wake twice - let waker = cx.waker(); - waker.wake_by_ref(); - waker.wake_by_ref(); - Poll::Ready(()) - } -} - -fn test_waker() { - let counter = Arc::new(Counter { - wakes: AtomicUsize::new(0), - }); - let waker = ArcWake::into_waker(counter.clone()); - assert_eq!(2, Arc::strong_count(&counter)); - { - let mut context = Context::from_waker(&waker); - assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&mut context)); - assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); - } - drop(waker); - assert_eq!(1, Arc::strong_count(&counter)); -} - -fn main() { - test_waker(); -} diff --git a/src/test/ui/async-await/futures-api.rs b/src/test/ui/async-await/futures-api.rs new file mode 100644 index 00000000000..a7da058de30 --- /dev/null +++ b/src/test/ui/async-await/futures-api.rs @@ -0,0 +1,61 @@ +// run-pass + +// aux-build:arc_wake.rs + +extern crate arc_wake; + +use std::future::Future; +use std::pin::Pin; +use std::sync::{ + Arc, + atomic::{self, AtomicUsize}, +}; +use std::task::{ + Context, Poll, +}; +use arc_wake::ArcWake; + +struct Counter { + wakes: AtomicUsize, +} + +impl ArcWake for Counter { + fn wake(self: Arc) { + Self::wake_by_ref(&self) + } + fn wake_by_ref(arc_self: &Arc) { + arc_self.wakes.fetch_add(1, atomic::Ordering::SeqCst); + } +} + +struct MyFuture; + +impl Future for MyFuture { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // Wake twice + let waker = cx.waker(); + waker.wake_by_ref(); + waker.wake_by_ref(); + Poll::Ready(()) + } +} + +fn test_waker() { + let counter = Arc::new(Counter { + wakes: AtomicUsize::new(0), + }); + let waker = ArcWake::into_waker(counter.clone()); + assert_eq!(2, Arc::strong_count(&counter)); + { + let mut context = Context::from_waker(&waker); + assert_eq!(Poll::Ready(()), Pin::new(&mut MyFuture).poll(&mut context)); + assert_eq!(2, counter.wakes.load(atomic::Ordering::SeqCst)); + } + drop(waker); + assert_eq!(1, Arc::strong_count(&counter)); +} + +fn main() { + test_waker(); +} -- cgit 1.4.1-3-g733a5 From 73aee89b47972da57b0f0b1c99ba4e2893ad0a20 Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Wed, 3 Jul 2019 23:10:03 +0800 Subject: Move the test async-fn-size-moved-locals to ui --- .../async-await/async-fn-size-moved-locals.rs | 98 -------------------- .../ui/async-await/async-fn-size-moved-locals.rs | 100 +++++++++++++++++++++ 2 files changed, 100 insertions(+), 98 deletions(-) delete mode 100644 src/test/run-pass/async-await/async-fn-size-moved-locals.rs create mode 100644 src/test/ui/async-await/async-fn-size-moved-locals.rs diff --git a/src/test/run-pass/async-await/async-fn-size-moved-locals.rs b/src/test/run-pass/async-await/async-fn-size-moved-locals.rs deleted file mode 100644 index 139be7fe013..00000000000 --- a/src/test/run-pass/async-await/async-fn-size-moved-locals.rs +++ /dev/null @@ -1,98 +0,0 @@ -// Test that we don't duplicate storage for futures moved around in .await, and -// for futures moved into other futures. -// -// The exact sizes can change by a few bytes (we'd like to know when they do). -// What we don't want to see is the wrong multiple of 1024 (the size of BigFut) -// being reflected in the size. -// -// See issue #59123 for a full explanation. - -// edition:2018 - -#![feature(async_await)] - -use std::future::Future; -use std::pin::Pin; -use std::task::{Context, Poll}; - -const BIG_FUT_SIZE: usize = 1024; -struct BigFut([u8; BIG_FUT_SIZE]); - -impl BigFut { - fn new() -> Self { - BigFut([0; BIG_FUT_SIZE]) - } } - -impl Drop for BigFut { - fn drop(&mut self) {} -} - -impl Future for BigFut { - type Output = (); - - fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll { - Poll::Ready(()) - } -} - -#[allow(dead_code)] -struct Joiner { - a: Option, - b: Option, - c: Option, -} - -impl Future for Joiner { - type Output = (); - - fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll { - Poll::Ready(()) - } -} - -fn noop() {} - -async fn single() { - let x = BigFut::new(); - x.await; -} - -async fn single_with_noop() { - let x = BigFut::new(); - noop(); - x.await; -} - -async fn joined() { - let a = BigFut::new(); - let b = BigFut::new(); - let c = BigFut::new(); - - let joiner = Joiner { - a: Some(a), - b: Some(b), - c: Some(c), - }; - joiner.await -} - -async fn joined_with_noop() { - let a = BigFut::new(); - let b = BigFut::new(); - let c = BigFut::new(); - - let joiner = Joiner { - a: Some(a), - b: Some(b), - c: Some(c), - }; - noop(); - joiner.await -} - -fn main() { - assert_eq!(1028, std::mem::size_of_val(&single())); - assert_eq!(1032, std::mem::size_of_val(&single_with_noop())); - assert_eq!(3084, std::mem::size_of_val(&joined())); - assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); -} 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 new file mode 100644 index 00000000000..8d24ffe7a7c --- /dev/null +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -0,0 +1,100 @@ +// Test that we don't duplicate storage for futures moved around in .await, and +// for futures moved into other futures. +// +// The exact sizes can change by a few bytes (we'd like to know when they do). +// What we don't want to see is the wrong multiple of 1024 (the size of BigFut) +// being reflected in the size. +// +// See issue #59123 for a full explanation. + +// run-pass + +// edition:2018 + +#![feature(async_await)] + +use std::future::Future; +use std::pin::Pin; +use std::task::{Context, Poll}; + +const BIG_FUT_SIZE: usize = 1024; +struct BigFut([u8; BIG_FUT_SIZE]); + +impl BigFut { + fn new() -> Self { + BigFut([0; BIG_FUT_SIZE]) + } } + +impl Drop for BigFut { + fn drop(&mut self) {} +} + +impl Future for BigFut { + type Output = (); + + fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll { + Poll::Ready(()) + } +} + +#[allow(dead_code)] +struct Joiner { + a: Option, + b: Option, + c: Option, +} + +impl Future for Joiner { + type Output = (); + + fn poll(self: Pin<&mut Self>, _ctx: &mut Context<'_>) -> Poll { + Poll::Ready(()) + } +} + +fn noop() {} + +async fn single() { + let x = BigFut::new(); + x.await; +} + +async fn single_with_noop() { + let x = BigFut::new(); + noop(); + x.await; +} + +async fn joined() { + let a = BigFut::new(); + let b = BigFut::new(); + let c = BigFut::new(); + + let joiner = Joiner { + a: Some(a), + b: Some(b), + c: Some(c), + }; + joiner.await +} + +async fn joined_with_noop() { + let a = BigFut::new(); + let b = BigFut::new(); + let c = BigFut::new(); + + let joiner = Joiner { + a: Some(a), + b: Some(b), + c: Some(c), + }; + noop(); + joiner.await +} + +fn main() { + assert_eq!(1028, std::mem::size_of_val(&single())); + assert_eq!(1032, std::mem::size_of_val(&single_with_noop())); + assert_eq!(3084, std::mem::size_of_val(&joined())); + assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); +} -- cgit 1.4.1-3-g733a5 From f115147fc481a4431116be526ce4dec315b1f871 Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Thu, 4 Jul 2019 21:04:20 +0800 Subject: 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 e4dfd4d829e..c6b2ed13b0a 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)] -- cgit 1.4.1-3-g733a5 From 70e8ba38b66ae2a52c67664eb10cfea5341b40da Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Wed, 10 Jul 2019 16:27:39 +0900 Subject: 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 67430e5bbda..513e22a788c 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -705,7 +705,8 @@ extern "rust-intrinsic" { they should be used through stabilized interfaces \ in the rest of the standard library", issue = "0")] - #[rustc_deprecated(reason = "no longer used by rustc, will be removed - use MaybeUnint instead", + #[rustc_deprecated(reason = "no longer used by rustc, will be removed - use MaybeUninit \ + instead", since = "1.38.0")] pub fn init() -> T; -- cgit 1.4.1-3-g733a5 From 128143c4e505aae88b7c6cde38aa7dab19e1e47c Mon Sep 17 00:00:00 2001 From: Andrew Xu Date: Wed, 10 Jul 2019 21:18:51 +0800 Subject: 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 8d24ffe7a7c..d0d4eb032fc 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 -- cgit 1.4.1-3-g733a5 From 6031a07a464eae202cc43fbb15fada094171488d Mon Sep 17 00:00:00 2001 From: Aleksa Sarai Date: Sat, 6 Jul 2019 00:51:19 +1000 Subject: 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 6d23963e141..0cecdd7ffa0 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -175,6 +175,7 @@ impl FileDesc { target_os = "emscripten", target_os = "fuchsia", target_os = "l4re", + target_os = "linux", target_os = "haiku")))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { @@ -187,6 +188,7 @@ impl FileDesc { target_os = "emscripten", target_os = "fuchsia", target_os = "l4re", + target_os = "linux", target_os = "haiku"))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { -- cgit 1.4.1-3-g733a5 From fa0809d3cdacae8638fd7beea2e85310902e21d3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Tue, 9 Jul 2019 11:15:05 +0200 Subject: 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 00000000000..9a4f8772822 --- /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 00000000000..5c865d76851 --- /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 00000000000..321b83c3459 --- /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 +} -- cgit 1.4.1-3-g733a5 From 48635226d8d71f18b09ea40f5cdbe34dbaaf378f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 18 Jun 2019 22:23:13 +0300 Subject: 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 -- src/librustdoc/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 1db18d30282..c09b2003f38 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -89,7 +89,6 @@ impl_stable_hash_for!(enum ::syntax::ext::base::MacroKind { Bang, Attr, Derive, - ProcMacroStub, }); diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 49116f3f171..974487ab9d2 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -29,7 +29,7 @@ use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant}; -use syntax::ext::base::{MacroKind, SyntaxExtension}; +use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; @@ -46,6 +46,20 @@ use log::debug; type Res = def::Res; +fn proc_macro_stub(item: &Item) -> Option<(Ident, Span)> { + if attr::contains_name(&item.attrs, sym::proc_macro) || + attr::contains_name(&item.attrs, sym::proc_macro_attribute) { + return Some((item.ident, item.span)); + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { + if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { + if let Some(ident) = nested_meta.ident() { + return Some((ident, ident.span)); + } + } + } + None +} + impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { @@ -456,22 +470,8 @@ impl<'a> Resolver<'a> { // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). - if attr::contains_name(&item.attrs, sym::proc_macro) || - attr::contains_name(&item.attrs, sym::proc_macro_attribute) { - let res = Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), res.def_id()); - self.define(parent, ident, MacroNS, (res, vis, sp, expansion)); - } - if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(trait_attr) = - attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = trait_attr.ident() { - let res = Res::Def( - DefKind::Macro(MacroKind::ProcMacroStub), - res.def_id(), - ); - self.define(parent, ident, MacroNS, (res, vis, ident.span, expansion)); - } - } + if let Some((ident, span)) = proc_macro_stub(item) { + self.define(parent, ident, MacroNS, (res, vis, span, expansion)); } } @@ -778,8 +778,6 @@ impl<'a> Resolver<'a> { crate fn opt_get_macro(&mut self, res: Res) -> Option> { let def_id = match res { - Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) => - return Some(self.non_macro_attr(true)), // some dummy extension Res::Def(DefKind::Macro(..), def_id) => def_id, Res::NonMacroAttr(attr_kind) => return Some(self.non_macro_attr(attr_kind == NonMacroAttrKind::Tool)), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 8f23c9813f7..a3e00bcb81a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -102,12 +102,11 @@ fn sub_namespace_match(candidate: Option, requirement: Option Some(SubNS::Bang), - MacroKind::Attr | MacroKind::Derive => Some(SubNS::AttrLike), - MacroKind::ProcMacroStub => None, + MacroKind::Bang => SubNS::Bang, + MacroKind::Attr | MacroKind::Derive => SubNS::AttrLike, }; - let requirement = requirement.and_then(|kind| sub_ns(kind)); - let candidate = candidate.and_then(|kind| sub_ns(kind)); + let candidate = candidate.map(sub_ns); + let requirement = requirement.map(sub_ns); // "No specific sub-namespace" means "matches anything" for both requirements and candidates. candidate.is_none() || requirement.is_none() || candidate == requirement } @@ -310,15 +309,15 @@ impl<'a> Resolver<'a> { let res = res?; match res { - Res::Def(DefKind::Macro(macro_kind), def_id) => { + Res::Def(DefKind::Macro(_), def_id) => { if let Some(node_id) = self.definitions.as_local_node_id(def_id) { self.unused_macros.remove(&node_id); } - if macro_kind == MacroKind::ProcMacroStub { - let msg = "can't use a procedural macro from the same crate that defines it"; - self.session.span_err(path.span, msg); - return Err(Determinacy::Determined); - } + } + Res::Def(DefKind::Fn, _) => { + let msg = "can't use a procedural macro from the same crate that defines it"; + self.session.span_err(path.span, msg); + return Err(Determinacy::Determined); } Res::NonMacroAttr(attr_kind) => { if kind == MacroKind::Attr { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 350bcc9dbc6..72e6614dc06 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 5f1a1b31616..9affc08141d 100644 --- a/src/librustdoc/html/item_type.rs +++ b/src/librustdoc/html/item_type.rs @@ -92,7 +92,6 @@ impl<'a> From<&'a clean::Item> for ItemType { MacroKind::Bang => ItemType::Macro, MacroKind::Attr => ItemType::ProcAttribute, MacroKind::Derive => ItemType::ProcDerive, - MacroKind::ProcMacroStub => unreachable!(), } clean::StrippedItem(..) => unreachable!(), } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 2d69c29dfae..5c6847b4141 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -2471,7 +2471,6 @@ impl<'a> fmt::Display for Item<'a> { MacroKind::Bang => write!(fmt, "Macro ")?, MacroKind::Attr => write!(fmt, "Attribute Macro ")?, MacroKind::Derive => write!(fmt, "Derive Macro ")?, - MacroKind::ProcMacroStub => unreachable!(), } clean::PrimitiveItem(..) => write!(fmt, "Primitive Type ")?, clean::StaticItem(..) | clean::ForeignStaticItem(..) => write!(fmt, "Static ")?, @@ -5092,7 +5091,6 @@ fn item_proc_macro(w: &mut fmt::Formatter<'_>, cx: &Context, it: &clean::Item, m } write!(w, "")?; } - _ => {} } document(w, cx, it) } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index bb85fe898da..acf7a951856 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 fa5faaf3ff5..009d681ed83 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -406,11 +406,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { // Struct and variant constructors and proc macro stubs always show up alongside // their definitions, we've already processed them so just discard these. - match path.res { - Res::Def(DefKind::Ctor(..), _) - | Res::SelfCtor(..) - | Res::Def(DefKind::Macro(MacroKind::ProcMacroStub), _) => return, - _ => {} + if let Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) = path.res { + return; } // If there was a private module in the current path then don't bother inlining diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index c0ba41b8af4..8d5e4a3369e 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -527,8 +527,6 @@ pub enum MacroKind { Attr, /// A derive attribute macro - #[derive(Foo)] Derive, - /// A view of a procedural macro from the same crate that defines it. - ProcMacroStub, } impl MacroKind { @@ -537,7 +535,6 @@ impl MacroKind { MacroKind::Bang => "macro", MacroKind::Attr => "attribute macro", MacroKind::Derive => "derive macro", - MacroKind::ProcMacroStub => "crate-local procedural macro", } } diff --git a/src/test/rustdoc/proc-macro.rs b/src/test/rustdoc/proc-macro.rs index 1e396f1be0e..4bd0b092b55 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; -- cgit 1.4.1-3-g733a5 From ec376c783e3a64445c4b55fb5980ae922319a916 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 19 Jun 2019 01:00:49 +0300 Subject: 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 8d5e4a3369e..09ff44115b4 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -24,6 +24,7 @@ use std::path::PathBuf; use std::rc::Rc; use std::default::Default; +pub use syntax_pos::hygiene::MacroKind; #[derive(Debug,Clone)] pub enum Annotatable { @@ -518,34 +519,6 @@ impl MacResult for DummyResult { } } -/// Represents different kinds of macro invocations that can be resolved. -#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] -pub enum MacroKind { - /// A bang macro - foo!() - Bang, - /// An attribute macro - #[foo] - Attr, - /// A derive attribute macro - #[derive(Foo)] - Derive, -} - -impl MacroKind { - pub fn descr(self) -> &'static str { - match self { - MacroKind::Bang => "macro", - MacroKind::Attr => "attribute macro", - MacroKind::Derive => "derive macro", - } - } - - pub fn article(self) -> &'static str { - match self { - MacroKind::Attr => "an", - _ => "a", - } - } -} - /// A syntax extension kind. pub enum SyntaxExtensionKind { /// A token-based function-like macro. diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index f52952ca402..6a2aba17a79 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -723,6 +723,34 @@ impl ExpnFormat { } } +/// The kind of macro invocation or definition. +#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] +pub enum MacroKind { + /// A bang macro `foo!()`. + Bang, + /// An attribute macro `#[foo]`. + Attr, + /// A derive macro `#[derive(Foo)]` + Derive, +} + +impl MacroKind { + pub fn descr(self) -> &'static str { + match self { + MacroKind::Bang => "macro", + MacroKind::Attr => "attribute macro", + MacroKind::Derive => "derive macro", + } + } + + pub fn article(self) -> &'static str { + match self { + MacroKind::Attr => "an", + _ => "a", + } + } +} + /// The kind of compiler desugaring. #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] pub enum CompilerDesugaringKind { -- cgit 1.4.1-3-g733a5 From 16918a8e28d4e7a476f31ff3d3c1e2d998c086af Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 19 Jun 2019 01:08:45 +0300 Subject: 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 +-- src/librustc_mir/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 2a9fd58f84b..549c34d961a 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -62,8 +62,7 @@ use syntax::ast::*; use syntax::errors; use syntax::ext::hygiene::{Mark, SyntaxContext}; use syntax::print::pprust; -use syntax::source_map::{self, respan, ExpnInfo, CompilerDesugaringKind, Spanned}; -use syntax::source_map::CompilerDesugaringKind::CondTemporary; +use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned}; use syntax::std_inject; use syntax::symbol::{kw, sym, Symbol}; use syntax::tokenstream::{TokenStream, TokenTree}; @@ -872,7 +871,7 @@ impl<'a> LoweringContext<'a> { /// allowed inside this span. fn mark_span_with_reason( &self, - reason: CompilerDesugaringKind, + reason: DesugaringKind, span: Span, allow_internal_unstable: Option>, ) -> Span { @@ -880,7 +879,7 @@ impl<'a> LoweringContext<'a> { mark.set_expn_info(ExpnInfo { def_site: Some(span), allow_internal_unstable, - ..ExpnInfo::default(source_map::CompilerDesugaring(reason), span, self.sess.edition()) + ..ExpnInfo::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) }); span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } @@ -1188,7 +1187,7 @@ impl<'a> LoweringContext<'a> { }; let unstable_span = self.mark_span_with_reason( - CompilerDesugaringKind::Async, + DesugaringKind::Async, span, self.allow_gen_future.clone(), ); @@ -1733,7 +1732,7 @@ impl<'a> LoweringContext<'a> { // Not tracking it makes lints in rustc and clippy very fragile, as // frequently opened issues show. let exist_ty_span = self.mark_span_with_reason( - CompilerDesugaringKind::ExistentialType, + DesugaringKind::ExistentialType, span, None, ); @@ -2603,7 +2602,7 @@ impl<'a> LoweringContext<'a> { let span = output.span(); let exist_ty_span = self.mark_span_with_reason( - CompilerDesugaringKind::Async, + DesugaringKind::Async, span, None, ); @@ -3275,7 +3274,7 @@ impl<'a> LoweringContext<'a> { }; let desugared_span = - this.mark_span_with_reason(CompilerDesugaringKind::Async, span, None); + this.mark_span_with_reason(DesugaringKind::Async, span, None); // Construct an argument representing `__argN: ` to replace the argument of the // async function. @@ -4410,7 +4409,9 @@ impl<'a> LoweringContext<'a> { _ => { // Lower condition: let cond = self.lower_expr(cond); - let span_block = self.mark_span_with_reason(CondTemporary, cond.span, None); + let span_block = self.mark_span_with_reason( + DesugaringKind::CondTemporary, cond.span, None + ); // Wrap in a construct equivalent to `{ let _t = $cond; _t }` // to preserve drop semantics since `if cond { ... }` does not // let temporaries live outside of `cond`. @@ -4469,7 +4470,9 @@ impl<'a> LoweringContext<'a> { // Lower condition: let cond = this.with_loop_condition_scope(|this| this.lower_expr(cond)); - let span_block = this.mark_span_with_reason(CondTemporary, cond.span, None); + let span_block = this.mark_span_with_reason( + DesugaringKind::CondTemporary, cond.span, None + ); // Wrap in a construct equivalent to `{ let _t = $cond; _t }` // to preserve drop semantics since `while cond { ... }` does not // let temporaries live outside of `cond`. @@ -4508,7 +4511,7 @@ impl<'a> LoweringContext<'a> { ExprKind::TryBlock(ref body) => { self.with_catch_scope(body.id, |this| { let unstable_span = this.mark_span_with_reason( - CompilerDesugaringKind::TryBlock, + DesugaringKind::TryBlock, body.span, this.allow_try_trait.clone(), ); @@ -4836,7 +4839,7 @@ impl<'a> LoweringContext<'a> { let mut head = self.lower_expr(head); let head_sp = head.span; let desugared_span = self.mark_span_with_reason( - CompilerDesugaringKind::ForLoop, + DesugaringKind::ForLoop, head_sp, None, ); @@ -4990,13 +4993,13 @@ impl<'a> LoweringContext<'a> { // } let unstable_span = self.mark_span_with_reason( - CompilerDesugaringKind::QuestionMark, + DesugaringKind::QuestionMark, e.span, self.allow_try_trait.clone(), ); let try_span = self.sess.source_map().end_point(e.span); let try_span = self.mark_span_with_reason( - CompilerDesugaringKind::QuestionMark, + DesugaringKind::QuestionMark, try_span, self.allow_try_trait.clone(), ); @@ -5811,12 +5814,12 @@ impl<'a> LoweringContext<'a> { } } let span = self.mark_span_with_reason( - CompilerDesugaringKind::Await, + DesugaringKind::Await, await_span, None, ); let gen_future_span = self.mark_span_with_reason( - CompilerDesugaringKind::Await, + DesugaringKind::Await, await_span, self.allow_gen_future.clone(), ); diff --git a/src/librustc/ich/impls_syntax.rs b/src/librustc/ich/impls_syntax.rs index c09b2003f38..f679a65c642 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -398,7 +398,7 @@ impl_stable_hash_for!(enum ::syntax_pos::hygiene::Transparency { impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { call_site, - format, + kind, def_site, default_transparency, allow_internal_unstable, @@ -407,13 +407,13 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { edition }); -impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnFormat { +impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind { MacroAttribute(sym), MacroBang(sym), - CompilerDesugaring(kind) + Desugaring(kind) }); -impl_stable_hash_for!(enum ::syntax_pos::hygiene::CompilerDesugaringKind { +impl_stable_hash_for!(enum ::syntax_pos::hygiene::DesugaringKind { CondTemporary, Async, Await, diff --git a/src/librustc/infer/error_reporting/need_type_info.rs b/src/librustc/infer/error_reporting/need_type_info.rs index 4426b5c0e85..770d5155777 100644 --- a/src/librustc/infer/error_reporting/need_type_info.rs +++ b/src/librustc/infer/error_reporting/need_type_info.rs @@ -5,7 +5,7 @@ use crate::infer::InferCtxt; use crate::infer::type_variable::TypeVariableOriginKind; use crate::ty::{self, Ty, Infer, TyVar}; use crate::ty::print::Print; -use syntax::source_map::CompilerDesugaringKind; +use syntax::source_map::DesugaringKind; use syntax_pos::Span; use errors::DiagnosticBuilder; @@ -194,12 +194,12 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { )); } else if let Some(pattern) = local_visitor.found_local_pattern { if let Some(simple_ident) = pattern.simple_ident() { - match pattern.span.compiler_desugaring_kind() { + match pattern.span.desugaring_kind() { None => labels.push(( pattern.span, format!("consider giving `{}` {}", simple_ident, suffix), )), - Some(CompilerDesugaringKind::ForLoop) => labels.push(( + Some(DesugaringKind::ForLoop) => labels.push(( pattern.span, "the element type for this iterator is not specified".to_owned(), )), diff --git a/src/librustc/lint/internal.rs b/src/librustc/lint/internal.rs index 34899736949..0b514f5927d 100644 --- a/src/librustc/lint/internal.rs +++ b/src/librustc/lint/internal.rs @@ -247,10 +247,10 @@ impl EarlyLintPass for LintPassImpl { } fn is_lint_pass_expansion(expn_info: &ExpnInfo) -> bool { - if expn_info.format.name() == sym::impl_lint_pass { + if expn_info.kind.descr() == sym::impl_lint_pass { true } else if let Some(info) = expn_info.call_site.ctxt().outer_expn_info() { - info.format.name() == sym::declare_lint_pass + info.kind.descr() == sym::declare_lint_pass } else { false } diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 59b08b832d2..2bf4f1d3cfb 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -35,7 +35,7 @@ use crate::util::nodemap::NodeMap; use errors::{DiagnosticBuilder, DiagnosticId}; use std::{hash, ptr}; use syntax::ast; -use syntax::source_map::{MultiSpan, ExpnFormat, CompilerDesugaringKind}; +use syntax::source_map::{MultiSpan, ExpnKind, DesugaringKind}; use syntax::early_buffered_lints::BufferedEarlyLintId; use syntax::edition::Edition; use syntax::symbol::{Symbol, sym}; @@ -883,11 +883,11 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { None => return false, }; - match info.format { - ExpnFormat::MacroAttribute(..) => true, // definitely a plugin - ExpnFormat::CompilerDesugaring(CompilerDesugaringKind::ForLoop) => false, - ExpnFormat::CompilerDesugaring(_) => true, // well, it's "external" - ExpnFormat::MacroBang(..) => { + match info.kind { + ExpnKind::MacroAttribute(..) => true, // definitely a plugin + ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, + ExpnKind::Desugaring(_) => true, // well, it's "external" + ExpnKind::MacroBang(..) => { let def_site = match info.def_site { Some(span) => span, // no span for the def_site means it's an external macro @@ -911,8 +911,8 @@ pub fn in_derive_expansion(span: Span) -> bool { None => return false, }; - match info.format { - ExpnFormat::MacroAttribute(symbol) => symbol.as_str().starts_with("derive("), + match info.kind { + ExpnKind::MacroAttribute(symbol) => symbol.as_str().starts_with("derive("), _ => false, } } diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 59a032d53cf..ff868bf2a2a 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -928,7 +928,7 @@ impl<'tcx> LocalDecl<'tcx> { /// `__next` from a `for` loop. #[inline] pub fn from_compiler_desugaring(&self) -> bool { - self.source_info.span.compiler_desugaring_kind().is_some() + self.source_info.span.desugaring_kind().is_some() } /// Creates a new `LocalDecl` for a temporary. diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d6cc68bcdab..fb7ed147445 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -36,7 +36,7 @@ use errors::{Applicability, DiagnosticBuilder}; use std::fmt; use syntax::ast; use syntax::symbol::sym; -use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnFormat}; +use syntax_pos::{DUMMY_SP, Span, ExpnInfo, ExpnKind}; impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn report_fulfillment_errors(&self, @@ -62,7 +62,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // if one is the result of a desugaring and the other is not. let mut span = error.obligation.cause.span; if let Some(ExpnInfo { - format: ExpnFormat::CompilerDesugaring(_), + kind: ExpnKind::Desugaring(_), def_site: Some(def_span), .. }) = span.ctxt().outer_expn_info() { @@ -373,9 +373,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { flags.push((sym::parent_trait, Some(t))); } - if let Some(k) = obligation.cause.span.compiler_desugaring_kind() { + if let Some(k) = obligation.cause.span.desugaring_kind() { flags.push((sym::from_desugaring, None)); - flags.push((sym::from_desugaring, Some(k.name().to_string()))); + flags.push((sym::from_desugaring, Some(k.descr().to_string()))); } let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index d402b0ddf6e..18bbb257128 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -8,7 +8,7 @@ use syntax::{ }, attr, source_map::{ - respan, ExpnInfo, MacroAttribute, + respan, ExpnInfo, ExpnKind, }, ext::{ base::{ExtCtxt, Resolver}, @@ -87,7 +87,8 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { // Create a fresh Mark for the new macro expansion we are about to do let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::global_allocator), item.span, self.sess.edition, &[sym::rustc_attrs] + ExpnKind::MacroAttribute(sym::global_allocator), item.span, self.sess.edition, + &[sym::rustc_attrs], )); // Tie the span to the macro expansion info we just created diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 34db080ef66..9a581cb03ec 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -33,7 +33,7 @@ use std::cell::{Cell, RefCell}; use std::fmt; use std::rc::Rc; use std::hash::{Hash, Hasher}; -use syntax::source_map::CompilerDesugaringKind; +use syntax::source_map::DesugaringKind; use syntax_pos::{MultiSpan, Span}; use errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use log::debug; @@ -734,8 +734,8 @@ impl BorrowckCtxt<'_, 'tcx> { }, moved_lp.ty)); } - if let (Some(CompilerDesugaringKind::ForLoop), Ok(snippet)) = ( - move_span.compiler_desugaring_kind(), + if let (Some(DesugaringKind::ForLoop), Ok(snippet)) = ( + move_span.desugaring_kind(), self.tcx.sess.source_map().span_to_snippet(move_span), ) { if !snippet.starts_with("&") { diff --git a/src/librustc_mir/borrow_check/conflict_errors.rs b/src/librustc_mir/borrow_check/conflict_errors.rs index f23cffeda68..7b5fce4abbc 100644 --- a/src/librustc_mir/borrow_check/conflict_errors.rs +++ b/src/librustc_mir/borrow_check/conflict_errors.rs @@ -10,7 +10,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::indexed_vec::Idx; use rustc_errors::{Applicability, DiagnosticBuilder}; use syntax_pos::Span; -use syntax::source_map::CompilerDesugaringKind; +use syntax::source_map::DesugaringKind; use super::nll::explain_borrow::BorrowExplanation; use super::nll::region_infer::{RegionName, RegionNameSource}; @@ -174,7 +174,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { format!("variable moved due to use{}", move_spans.describe()), ); } - if Some(CompilerDesugaringKind::ForLoop) == move_span.compiler_desugaring_kind() { + if Some(DesugaringKind::ForLoop) == move_span.desugaring_kind() { if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { err.span_suggestion( move_span, diff --git a/src/librustc_mir/borrow_check/mod.rs b/src/librustc_mir/borrow_check/mod.rs index 25ac93cc242..31a9766af30 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 effd69dc61d..fab2537f9d8 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -37,7 +37,6 @@ use syntax::parse::lexer::comments::strip_doc_comment_decoration; use syntax::print::pprust; use syntax::visit::{self, Visitor}; use syntax::print::pprust::{arg_to_string, ty_to_string}; -use syntax::source_map::MacroAttribute; use syntax_pos::*; use json_dumper::JsonDumper; @@ -845,7 +844,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let callee_span = callee.def_site?; // Ignore attribute macros, their spans are usually mangled - if let MacroAttribute(_) = callee.format { + if let ExpnKind::MacroAttribute(_) = callee.kind { return None; } @@ -870,7 +869,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let callee_span = self.span_from_span(callee_span); Some(MacroRef { span: callsite_span, - qualname: callee.format.name().to_string(), // FIXME: generate the real qualname + qualname: callee.kind.descr().to_string(), // FIXME: generate the real qualname callee_span, }) } diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index d24f92a6faf..de42a6a35c8 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -15,7 +15,7 @@ use syntax::ast; use syntax::source_map::Spanned; use syntax::util::lev_distance::find_best_match_for_name; use syntax_pos::Span; -use syntax_pos::hygiene::CompilerDesugaringKind; +use syntax_pos::hygiene::DesugaringKind; use std::collections::hash_map::Entry::{Occupied, Vacant}; use std::cmp; @@ -184,7 +184,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // In the case of `if`- and `while`-expressions we've already checked // that `scrutinee: bool`. We know that the pattern is `true`, // so an error here would be a duplicate and from the wrong POV. - s.is_compiler_desugaring(CompilerDesugaringKind::CondTemporary) + s.is_desugaring(DesugaringKind::CondTemporary) }) .is_some()); } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 4acba6d38fa..d32ee67f745 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -119,7 +119,7 @@ use rustc::ty::subst::{UnpackedKind, Subst, InternalSubsts, SubstsRef, UserSelfT use rustc::ty::util::{Representability, IntTypeExt, Discr}; use rustc::ty::layout::VariantIdx; use syntax_pos::{self, BytePos, Span, MultiSpan}; -use syntax_pos::hygiene::CompilerDesugaringKind; +use syntax_pos::hygiene::DesugaringKind; use syntax::ast; use syntax::attr; use syntax::feature_gate::{GateIssue, emit_feature_err}; @@ -2165,7 +2165,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If span arose from a desugaring of `if` or `while`, then it is the condition itself, // which diverges, that we are about to lint on. This gives suboptimal diagnostics. // Instead, stop here so that the `if`- or `while`-expression's block is linted instead. - !span.is_compiler_desugaring(CompilerDesugaringKind::CondTemporary) { + !span.is_desugaring(DesugaringKind::CondTemporary) { self.diverges.set(Diverges::WarnedAlways); debug!("warn_if_unreachable: id={:?} span={:?} kind={}", id, span, kind); diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 09ff44115b4..0c986574cec 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -15,7 +15,7 @@ use crate::tokenstream::{self, TokenStream}; use errors::{DiagnosticBuilder, DiagnosticId}; use smallvec::{smallvec, SmallVec}; use syntax_pos::{Span, MultiSpan, DUMMY_SP}; -use syntax_pos::hygiene::{ExpnInfo, ExpnFormat}; +use syntax_pos::hygiene::{ExpnInfo, ExpnKind}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{self, Lrc}; @@ -642,18 +642,18 @@ impl SyntaxExtension { } } - fn expn_format(&self, symbol: Symbol) -> ExpnFormat { + fn expn_kind(&self, descr: Symbol) -> ExpnKind { match self.kind { SyntaxExtensionKind::Bang(..) | - SyntaxExtensionKind::LegacyBang(..) => ExpnFormat::MacroBang(symbol), - _ => ExpnFormat::MacroAttribute(symbol), + SyntaxExtensionKind::LegacyBang(..) => ExpnKind::MacroBang(descr), + _ => ExpnKind::MacroAttribute(descr), } } - pub fn expn_info(&self, call_site: Span, format: &str) -> ExpnInfo { + pub fn expn_info(&self, call_site: Span, descr: &str) -> ExpnInfo { ExpnInfo { call_site, - format: self.expn_format(Symbol::intern(format)), + kind: self.expn_kind(Symbol::intern(descr)), def_site: Some(self.span), default_transparency: self.default_transparency, allow_internal_unstable: self.allow_internal_unstable.clone(), @@ -780,7 +780,7 @@ impl<'a> ExtCtxt<'a> { let mut last_macro = None; loop { if ctxt.outer_expn_info().map_or(None, |info| { - if info.format.name() == sym::include { + if info.kind.descr() == sym::include { // Stop going up the backtrace once include! is encountered return None; } diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 2a56f3dd756..24050be792b 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 053686b8b1f..879069c1418 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -506,7 +506,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let suggested_limit = self.cx.ecfg.recursion_limit * 2; let mut err = self.cx.struct_span_err(info.call_site, &format!("recursion limit reached while expanding the macro `{}`", - info.format.name())); + info.kind.descr())); err.help(&format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate", suggested_limit)); diff --git a/src/libsyntax/source_map.rs b/src/libsyntax/source_map.rs index ac30cbb471a..bbf62ef1e23 100644 --- a/src/libsyntax/source_map.rs +++ b/src/libsyntax/source_map.rs @@ -7,10 +7,8 @@ //! within the SourceMap, which upon request can be converted to line and column //! information, source code snippets, etc. - pub use syntax_pos::*; -pub use syntax_pos::hygiene::{ExpnFormat, ExpnInfo}; -pub use ExpnFormat::*; +pub use syntax_pos::hygiene::{ExpnKind, ExpnInfo}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 6630bf90815..7ee073117e9 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -3,7 +3,7 @@ use crate::attr; use crate::edition::Edition; use crate::ext::hygiene::{Mark, SyntaxContext}; use crate::symbol::{Ident, Symbol, kw, sym}; -use crate::source_map::{ExpnInfo, MacroAttribute, dummy_spanned, respan}; +use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan}; use crate::ptr::P; use crate::tokenstream::TokenStream; @@ -17,7 +17,7 @@ use syntax_pos::{DUMMY_SP, Span}; fn ignored_span(sp: Span, edition: Edition) -> Span { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(Symbol::intern("std_inject")), sp, edition, &[sym::prelude_import] + ExpnKind::MacroAttribute(Symbol::intern("std_inject")), sp, edition, &[sym::prelude_import] )); sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index c717f140ca3..35a1a552a13 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -15,7 +15,7 @@ use smallvec::{smallvec, SmallVec}; use syntax_pos::{DUMMY_SP, NO_EXPANSION, Span, SourceFile, BytePos}; use crate::attr::{self, HasAttrs}; -use crate::source_map::{self, SourceMap, ExpnInfo, MacroAttribute, dummy_spanned, respan}; +use crate::source_map::{self, SourceMap, ExpnInfo, ExpnKind, dummy_spanned, respan}; use crate::config; use crate::entry::{self, EntryPointType}; use crate::ext::base::{ExtCtxt, Resolver}; @@ -280,7 +280,7 @@ fn generate_test_harness(sess: &ParseSess, }; mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::test_case), DUMMY_SP, sess.edition, + ExpnKind::MacroAttribute(sym::test_case), DUMMY_SP, sess.edition, &[sym::main, sym::test, sym::rustc_attrs], )); diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs index 45e65288a24..dee8f4b3eb5 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -4,7 +4,7 @@ use crate::deriving; use syntax::ast::{self, Ident}; use syntax::attr; -use syntax::source_map::{ExpnInfo, MacroAttribute, respan}; +use syntax::source_map::{ExpnInfo, ExpnKind, respan}; use syntax::ext::base::ExtCtxt; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; @@ -348,7 +348,7 @@ fn mk_decls( ) -> P { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, + ExpnKind::MacroAttribute(sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, &[sym::rustc_attrs, Symbol::intern("proc_macro_internals")], )); let span = DUMMY_SP.apply_mark(mark); diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 24d3055e711..7f4f1fd7e01 100644 --- a/src/libsyntax_ext/test.rs +++ b/src/libsyntax_ext/test.rs @@ -9,7 +9,7 @@ use syntax::ast; use syntax::print::pprust; use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; -use syntax::source_map::{ExpnInfo, MacroAttribute}; +use syntax::source_map::{ExpnInfo, ExpnKind}; use std::iter; pub fn expand_test( @@ -63,7 +63,7 @@ pub fn expand_test_or_bench( let (sp, attr_sp) = { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::test), attr_sp, cx.parse_sess.edition, + ExpnKind::MacroAttribute(sym::test), attr_sp, cx.parse_sess.edition, &[sym::rustc_attrs, sym::test], )); (item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)), diff --git a/src/libsyntax_ext/test_case.rs b/src/libsyntax_ext/test_case.rs index 186673c142f..5f88e2e098a 100644 --- a/src/libsyntax_ext/test_case.rs +++ b/src/libsyntax_ext/test_case.rs @@ -16,7 +16,7 @@ use syntax::ast; use syntax::source_map::respan; use syntax::symbol::sym; use syntax_pos::Span; -use syntax::source_map::{ExpnInfo, MacroAttribute}; +use syntax::source_map::{ExpnInfo, ExpnKind}; pub fn expand( ecx: &mut ExtCtxt<'_>, @@ -29,7 +29,7 @@ pub fn expand( let sp = { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - MacroAttribute(sym::test_case), attr_sp, ecx.parse_sess.edition, + ExpnKind::MacroAttribute(sym::test_case), attr_sp, ecx.parse_sess.edition, &[sym::test, sym::rustc_attrs], )); attr_sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 6a2aba17a79..f36a4d5816e 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -162,7 +162,7 @@ impl Mark { HygieneData::with(|data| { if data.default_transparency(self) == Transparency::Opaque { if let Some(expn_info) = &data.marks[self.0 as usize].expn_info { - if let ExpnFormat::MacroAttribute(name) = expn_info.format { + if let ExpnKind::MacroAttribute(name) = expn_info.kind { if name.as_str().starts_with("derive(") { return true; } @@ -654,7 +654,7 @@ pub struct ExpnInfo { /// pointing to the `foo!` invocation. pub call_site: Span, /// The format with which the macro was invoked. - pub format: ExpnFormat, + pub kind: ExpnKind, // --- The part specific to the macro/desugaring definition. // --- FIXME: Share it between expansions with the same definition. @@ -681,10 +681,10 @@ pub struct ExpnInfo { impl ExpnInfo { /// Constructs an expansion info with default properties. - pub fn default(format: ExpnFormat, call_site: Span, edition: Edition) -> ExpnInfo { + pub fn default(kind: ExpnKind, call_site: Span, edition: Edition) -> ExpnInfo { ExpnInfo { call_site, - format, + kind, def_site: None, default_transparency: Transparency::SemiTransparent, allow_internal_unstable: None, @@ -694,31 +694,31 @@ impl ExpnInfo { } } - pub fn with_unstable(format: ExpnFormat, call_site: Span, edition: Edition, + pub fn with_unstable(kind: ExpnKind, call_site: Span, edition: Edition, allow_internal_unstable: &[Symbol]) -> ExpnInfo { ExpnInfo { allow_internal_unstable: Some(allow_internal_unstable.into()), - ..ExpnInfo::default(format, call_site, edition) + ..ExpnInfo::default(kind, call_site, edition) } } } /// The source of expansion. #[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] -pub enum ExpnFormat { +pub enum ExpnKind { /// e.g., #[derive(...)] MacroAttribute(Symbol), /// e.g., `format!()` MacroBang(Symbol), /// Desugaring done by the compiler during HIR lowering. - CompilerDesugaring(CompilerDesugaringKind) + Desugaring(DesugaringKind) } -impl ExpnFormat { - pub fn name(&self) -> Symbol { +impl ExpnKind { + pub fn descr(&self) -> Symbol { match *self { - ExpnFormat::MacroBang(name) | ExpnFormat::MacroAttribute(name) => name, - ExpnFormat::CompilerDesugaring(kind) => kind.name(), + ExpnKind::MacroBang(name) | ExpnKind::MacroAttribute(name) => name, + ExpnKind::Desugaring(kind) => kind.descr(), } } } @@ -753,7 +753,7 @@ impl MacroKind { /// The kind of compiler desugaring. #[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] -pub enum CompilerDesugaringKind { +pub enum DesugaringKind { /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`. /// However, we do not want to blame `c` for unreachability but rather say that `i` /// is unreachable. This desugaring kind allows us to avoid blaming `c`. @@ -770,16 +770,16 @@ pub enum CompilerDesugaringKind { ForLoop, } -impl CompilerDesugaringKind { - pub fn name(self) -> Symbol { +impl DesugaringKind { + pub fn descr(self) -> Symbol { Symbol::intern(match self { - CompilerDesugaringKind::CondTemporary => "if and while condition", - CompilerDesugaringKind::Async => "async", - CompilerDesugaringKind::Await => "await", - CompilerDesugaringKind::QuestionMark => "?", - CompilerDesugaringKind::TryBlock => "try block", - CompilerDesugaringKind::ExistentialType => "existential type", - CompilerDesugaringKind::ForLoop => "for loop", + DesugaringKind::CondTemporary => "if and while condition", + DesugaringKind::Async => "async", + DesugaringKind::Await => "await", + DesugaringKind::QuestionMark => "?", + DesugaringKind::TryBlock => "try block", + DesugaringKind::ExistentialType => "existential type", + DesugaringKind::ForLoop => "for loop", }) } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 07b9f609320..d4c1958f7e2 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -27,7 +27,7 @@ extern crate serialize as rustc_serialize; // used by deriving pub mod edition; use edition::Edition; pub mod hygiene; -pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnFormat, CompilerDesugaringKind}; +pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnKind, DesugaringKind}; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -403,10 +403,10 @@ impl Span { } /// Checks if this span arises from a compiler desugaring of kind `kind`. - pub fn is_compiler_desugaring(&self, kind: CompilerDesugaringKind) -> bool { + pub fn is_desugaring(&self, kind: DesugaringKind) -> bool { match self.ctxt().outer_expn_info() { - Some(info) => match info.format { - ExpnFormat::CompilerDesugaring(k) => k == kind, + Some(info) => match info.kind { + ExpnKind::Desugaring(k) => k == kind, _ => false, }, None => false, @@ -415,10 +415,10 @@ impl Span { /// Returns the compiler desugaring that created this span, or `None` /// if this span is not from a desugaring. - pub fn compiler_desugaring_kind(&self) -> Option { + pub fn desugaring_kind(&self) -> Option { match self.ctxt().outer_expn_info() { - Some(info) => match info.format { - ExpnFormat::CompilerDesugaring(k) => Some(k), + Some(info) => match info.kind { + ExpnKind::Desugaring(k) => Some(k), _ => None }, None => None @@ -441,14 +441,14 @@ impl Span { while let Some(info) = self.ctxt().outer_expn_info() { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { - let (pre, post) = match info.format { - ExpnFormat::MacroAttribute(..) => ("#[", "]"), - ExpnFormat::MacroBang(..) => ("", "!"), - ExpnFormat::CompilerDesugaring(..) => ("desugaring of `", "`"), + let (pre, post) = match info.kind { + ExpnKind::MacroAttribute(..) => ("#[", "]"), + ExpnKind::MacroBang(..) => ("", "!"), + ExpnKind::Desugaring(..) => ("desugaring of `", "`"), }; result.push(MacroBacktrace { call_site: info.call_site, - macro_decl_name: format!("{}{}{}", pre, info.format.name(), post), + macro_decl_name: format!("{}{}{}", pre, info.kind.descr(), post), def_site_span: info.def_site, }); } -- cgit 1.4.1-3-g733a5 From f1d4ebf01505877ff36ba63f8a26ea8ea0973969 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 20 Jun 2019 02:33:39 +0300 Subject: Remove unnecessary expansions created by `#[test_case/test/bench]` The expansions were created to allow unstable things inside `#[test_case/test/bench]`, but that's not a proper way to do that. Put the required `allow_internal_unstable`s into the macros' properties instead. --- src/libcore/macros.rs | 3 +++ src/libsyntax_ext/lib.rs | 24 ++++++++++++++++-------- src/libsyntax_ext/test.rs | 14 +++----------- src/libsyntax_ext/test_case.rs | 14 ++------------ 4 files changed, 24 insertions(+), 31 deletions(-) diff --git a/src/libcore/macros.rs b/src/libcore/macros.rs index 2e999a0682b..293a2dd9492 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 62530f4fe7b..da0f8ca6da0 100644 --- a/src/libsyntax_ext/lib.rs +++ b/src/libsyntax_ext/lib.rs @@ -72,6 +72,7 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, let mut register = |name, ext| { resolver.add_builtin(ast::Ident::with_empty_ctxt(name), Lrc::new(ext)); }; + macro_rules! register { ($( $name:ident: $f:expr, )*) => { $( register(sym::$name, SyntaxExtension::default( @@ -125,24 +126,31 @@ pub fn register_builtins(resolver: &mut dyn syntax::ext::base::Resolver, trace_macros: trace_macros::expand_trace_macros, } + let allow_internal_unstable = Some([sym::test, sym::rustc_attrs][..].into()); register(sym::test_case, SyntaxExtension { stability: Some(Stability::unstable( sym::custom_test_frameworks, Some(Symbol::intern(EXPLAIN_CUSTOM_TEST_FRAMEWORKS)), 50297, )), + allow_internal_unstable: allow_internal_unstable.clone(), ..SyntaxExtension::default( SyntaxExtensionKind::LegacyAttr(Box::new(test_case::expand)), edition ) }); - register(sym::test, SyntaxExtension::default( - SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_test)), edition - )); - register(sym::bench, SyntaxExtension::default( - SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_bench)), edition - )); - - // format_args uses `unstable` things internally. + register(sym::test, SyntaxExtension { + allow_internal_unstable: allow_internal_unstable.clone(), + ..SyntaxExtension::default( + SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_test)), edition + ) + }); + register(sym::bench, SyntaxExtension { + allow_internal_unstable, + ..SyntaxExtension::default( + SyntaxExtensionKind::LegacyAttr(Box::new(test::expand_bench)), edition + ) + }); + let allow_internal_unstable = Some([sym::fmt_internals][..].into()); register(sym::format_args, SyntaxExtension { allow_internal_unstable: allow_internal_unstable.clone(), diff --git a/src/libsyntax_ext/test.rs b/src/libsyntax_ext/test.rs index 7f4f1fd7e01..c5c5ef57b31 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 5f88e2e098a..af2cf42e04b 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(); -- cgit 1.4.1-3-g733a5 From 62a1f5dbc0bbcf875b21dce643ae8b2ae971c74e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 20 Jun 2019 10:34:51 +0300 Subject: 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 f36a4d5816e..f8318f54320 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -31,7 +31,7 @@ use crate::edition::Edition; use crate::symbol::{kw, Symbol}; use serialize::{Encodable, Decodable, Encoder, Decoder}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; use std::fmt; @@ -130,32 +130,6 @@ impl Mark { HygieneData::with(|data| data.is_descendant_of(self, data.outer(ctxt))) } - /// Computes a mark such that both input marks are descendants of (or equal to) the returned - /// mark. That is, the following holds: - /// - /// ```rust - /// let la = least_ancestor(a, b); - /// assert!(a.is_descendant_of(la)) - /// assert!(b.is_descendant_of(la)) - /// ``` - pub fn least_ancestor(mut a: Mark, mut b: Mark) -> Mark { - HygieneData::with(|data| { - // Compute the path from a to the root - let mut a_path = FxHashSet::::default(); - while a != Mark::root() { - a_path.insert(a); - a = data.marks[a.0 as usize].parent; - } - - // While the path from b to the root hasn't intersected, move up the tree - while !a_path.contains(&b) { - b = data.marks[b.0 as usize].parent; - } - - b - }) - } - // Used for enabling some compatibility fallback in resolve. #[inline] pub fn looks_like_proc_macro_derive(self) -> bool { -- cgit 1.4.1-3-g733a5 From a138e9d625bf83c45d3835b12d7689b730dc4e9a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 29 Jun 2019 02:30:53 +0300 Subject: 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 a3e00bcb81a..61300e3ee3c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -242,13 +242,6 @@ impl<'a> base::Resolver for Resolver<'a> { Ok(Some(ext)) } - fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark, - derives_in_scope: Vec, force: bool) - -> Result, Determinacy> { - let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - Ok(self.resolve_macro_to_res(path, kind, &parent_scope, false, force)?.1) - } - fn check_unused_macros(&self) { for (&node_id, &span) in self.unused_macros.iter() { self.session.buffer_lint( diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 0c986574cec..267046655ff 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -680,9 +680,6 @@ pub trait Resolver { fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) -> Result>, Determinacy>; - fn resolve_macro_path(&mut self, path: &ast::Path, kind: MacroKind, invoc_id: Mark, - derives_in_scope: Vec, force: bool) - -> Result, Determinacy>; fn check_unused_macros(&self); } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 879069c1418..bb7d7352e05 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -208,6 +208,7 @@ pub enum InvocationKind { Derive { path: Path, item: Annotatable, + item_with_markers: Annotatable, }, } @@ -362,19 +363,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { derives.reserve(traits.len()); invocations.reserve(traits.len()); - for path in &traits { + for path in traits { let mark = Mark::fresh(self.cx.current_expansion.mark); derives.push(mark); - let item = match self.cx.resolver.resolve_macro_path( - path, MacroKind::Derive, Mark::root(), Vec::new(), false) { - Ok(ext) => match ext.kind { - SyntaxExtensionKind::LegacyDerive(..) => item_with_markers.clone(), - _ => item.clone(), - }, - _ => item.clone(), - }; invocations.push(Invocation { - kind: InvocationKind::Derive { path: path.clone(), item }, + kind: InvocationKind::Derive { + path, + item: item.clone(), + item_with_markers: item_with_markers.clone(), + }, fragment_kind: invoc.fragment_kind, expansion_data: ExpansionData { mark, @@ -737,7 +734,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ext: &SyntaxExtension) -> Option { let (path, item) = match invoc.kind { - InvocationKind::Derive { path, item } => (path, item), + InvocationKind::Derive { path, item, item_with_markers } => match ext.kind { + SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers), + _ => (path, item), + } _ => unreachable!(), }; if !item.derive_allowed() { -- cgit 1.4.1-3-g733a5 From 3eafaae510a71a76eedcc2909e7c908bd49d5c46 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 30 Jun 2019 03:05:52 +0300 Subject: 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 +- .../run-pass-fulldeps/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 549c34d961a..c44fd30be85 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -877,7 +877,7 @@ impl<'a> LoweringContext<'a> { ) -> Span { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo { - def_site: Some(span), + def_site: span, allow_internal_unstable, ..ExpnInfo::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) }); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 2bf4f1d3cfb..9876d6c1fa5 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 fb7ed147445..a7dfbd688c1 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -61,12 +61,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // We want to ignore desugarings here: spans are equivalent even // if one is the result of a desugaring and the other is not. let mut span = error.obligation.cause.span; - if let Some(ExpnInfo { - kind: ExpnKind::Desugaring(_), - def_site: Some(def_span), - .. - }) = span.ctxt().outer_expn_info() { - span = def_span; + if let Some(ExpnInfo { kind: ExpnKind::Desugaring(_), def_site, .. }) + = span.ctxt().outer_expn_info() { + span = def_site; } error_map.entry(span).or_default().push( diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 83a0fb486fd..361b5cd9357 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -723,39 +723,37 @@ impl EmitterWriter { for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() { // Only show macro locations that are local // and display them like a span_note - if let Some(def_site) = trace.def_site_span { - if def_site.is_dummy() { - continue; - } - if always_backtrace { - new_labels.push((def_site, - format!("in this expansion of `{}`{}", - trace.macro_decl_name, - if backtrace_len > 2 { - // if backtrace_len == 1 it'll be pointed - // at by "in this macro invocation" - format!(" (#{})", i + 1) - } else { - String::new() - }))); - } - // Check to make sure we're not in any <*macros> - if !sm.span_to_filename(def_site).is_macros() && - !trace.macro_decl_name.starts_with("desugaring of ") && - !trace.macro_decl_name.starts_with("#[") || - always_backtrace { - new_labels.push((trace.call_site, - format!("in this macro invocation{}", - if backtrace_len > 2 && always_backtrace { - // only specify order when the macro - // backtrace is multiple levels deep - format!(" (#{})", i + 1) - } else { - String::new() - }))); - if !always_backtrace { - break; - } + if trace.def_site_span.is_dummy() { + continue; + } + if always_backtrace { + new_labels.push((trace.def_site_span, + format!("in this expansion of `{}`{}", + trace.macro_decl_name, + if backtrace_len > 2 { + // if backtrace_len == 1 it'll be pointed + // at by "in this macro invocation" + format!(" (#{})", i + 1) + } else { + String::new() + }))); + } + // Check to make sure we're not in any <*macros> + if !sm.span_to_filename(trace.def_site_span).is_macros() && + !trace.macro_decl_name.starts_with("desugaring of ") && + !trace.macro_decl_name.starts_with("#[") || + always_backtrace { + new_labels.push((trace.call_site, + format!("in this macro invocation{}", + if backtrace_len > 2 && always_backtrace { + // only specify order when the macro + // backtrace is multiple levels deep + format!(" (#{})", i + 1) + } else { + String::new() + }))); + if !always_backtrace { + break; } } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index fab2537f9d8..aeaee1887b9 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -841,7 +841,6 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let callsite = span.source_callsite(); let callsite_span = self.span_from_span(callsite); let callee = span.source_callee()?; - let callee_span = callee.def_site?; // Ignore attribute macros, their spans are usually mangled if let ExpnKind::MacroAttribute(_) = callee.kind { @@ -855,7 +854,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { .sess .imported_macro_spans .borrow() - .get(&callee_span) + .get(&callee.def_site) { let &(ref mac_name, mac_span) = mac; let mac_span = self.span_from_span(mac_span); @@ -866,7 +865,7 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { }); } - let callee_span = self.span_from_span(callee_span); + let callee_span = self.span_from_span(callee.def_site); Some(MacroRef { span: callsite_span, qualname: callee.kind.descr().to_string(), // FIXME: generate the real qualname diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 267046655ff..2f8d6f00ba7 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -219,7 +219,6 @@ pub trait TTMacroExpander { ecx: &'cx mut ExtCtxt<'_>, span: Span, input: TokenStream, - def_span: Option, ) -> Box; } @@ -236,7 +235,6 @@ impl TTMacroExpander for F ecx: &'cx mut ExtCtxt<'_>, span: Span, input: TokenStream, - _def_span: Option, ) -> Box { struct AvoidInterpolatedIdents; @@ -654,7 +652,7 @@ impl SyntaxExtension { ExpnInfo { call_site, kind: self.expn_kind(Symbol::intern(descr)), - def_site: Some(self.span), + def_site: self.span, default_transparency: self.default_transparency, allow_internal_unstable: self.allow_internal_unstable.clone(), allow_internal_unsafe: self.allow_internal_unsafe, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index bb7d7352e05..06ff2bc655c 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -673,7 +673,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { result } SyntaxExtensionKind::LegacyBang(expander) => { - let tok_result = expander.expand(self.cx, span, mac.node.stream(), Some(ext.span)); + let tok_result = expander.expand(self.cx, span, mac.node.stream()); kind.make_from(tok_result) } diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index 665c794422d..5c6438a7ef5 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -88,6 +88,7 @@ impl<'a> ParserAnyMacro<'a> { struct MacroRulesMacroExpander { name: ast::Ident, + span: Span, lhses: Vec, rhses: Vec, valid: bool, @@ -99,12 +100,11 @@ impl TTMacroExpander for MacroRulesMacroExpander { cx: &'cx mut ExtCtxt<'_>, sp: Span, input: TokenStream, - def_span: Option, ) -> Box { if !self.valid { return DummyResult::any(sp); } - generic_extension(cx, sp, def_span, self.name, input, &self.lhses, &self.rhses) + generic_extension(cx, sp, self.span, self.name, input, &self.lhses, &self.rhses) } } @@ -117,7 +117,7 @@ fn trace_macros_note(cx: &mut ExtCtxt<'_>, sp: Span, message: String) { fn generic_extension<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, - def_span: Option, + def_span: Span, name: ast::Ident, arg: TokenStream, lhses: &[quoted::TokenTree], @@ -199,10 +199,8 @@ fn generic_extension<'cx>( let span = token.span.substitute_dummy(sp); let mut err = cx.struct_span_err(span, &parse_failure_msg(&token)); err.span_label(span, label); - if let Some(sp) = def_span { - if cx.source_map().span_to_filename(sp).is_real() && !sp.is_dummy() { - err.span_label(cx.source_map().def_span(sp), "when calling this macro"); - } + if !def_span.is_dummy() && cx.source_map().span_to_filename(def_span).is_real() { + err.span_label(cx.source_map().def_span(def_span), "when calling this macro"); } // Check whether there's a missing comma in this macro call, like `println!("{}" a);` @@ -377,7 +375,7 @@ pub fn compile( } let expander: Box<_> = - Box::new(MacroRulesMacroExpander { name: def.ident, lhses, rhses, valid }); + Box::new(MacroRulesMacroExpander { name: def.ident, span: def.span, lhses, rhses, valid }); let (default_transparency, transparency_error) = attr::find_transparency(&def.attrs, body.legacy); diff --git a/src/libsyntax/json.rs b/src/libsyntax/json.rs index 767ab74355e..ec0222d90eb 100644 --- a/src/libsyntax/json.rs +++ b/src/libsyntax/json.rs @@ -170,7 +170,7 @@ struct DiagnosticSpanMacroExpansion { macro_decl_name: String, /// span where macro was defined (if known) - def_site_span: Option, + def_site_span: DiagnosticSpan, } #[derive(RustcEncodable)] @@ -300,14 +300,13 @@ impl DiagnosticSpan { None, backtrace, je); - let def_site_span = bt.def_site_span.map(|sp| { - Self::from_span_full(sp, + let def_site_span = + Self::from_span_full(bt.def_site_span, false, None, None, vec![].into_iter(), - je) - }); + je); Box::new(DiagnosticSpanMacroExpansion { span: call_site, macro_decl_name: bt.macro_decl_name, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index f8318f54320..63b692ccdcb 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -26,7 +26,7 @@ // trigger runtime aborts. (Fortunately these are obvious and easy to fix.) use crate::GLOBALS; -use crate::Span; +use crate::{Span, DUMMY_SP}; use crate::edition::Edition; use crate::symbol::{kw, Symbol}; @@ -632,11 +632,9 @@ pub struct ExpnInfo { // --- The part specific to the macro/desugaring definition. // --- FIXME: Share it between expansions with the same definition. - /// The span of the macro definition itself. The macro may not - /// have a sensible definition span (e.g., something defined - /// completely inside libsyntax) in which case this is None. + /// The span of the macro definition (possibly dummy). /// This span serves only informational purpose and is not used for resolution. - pub def_site: Option, + pub def_site: Span, /// Transparency used by `apply_mark` for mark with this expansion info by default. pub default_transparency: Transparency, /// List of #[unstable]/feature-gated features that the macro is allowed to use @@ -659,7 +657,7 @@ impl ExpnInfo { ExpnInfo { call_site, kind, - def_site: None, + def_site: DUMMY_SP, default_transparency: Transparency::SemiTransparent, allow_internal_unstable: None, allow_internal_unsafe: false, diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index d4c1958f7e2..1369fca3b4a 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 7cbfef52b4a..36cee82893a 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))) -- cgit 1.4.1-3-g733a5 From 4dcf9b15c451e2994ee92cba6efdd2779a931b99 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 30 Jun 2019 14:57:34 +0300 Subject: 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 63b692ccdcb..67dcdabe701 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -36,10 +36,10 @@ use rustc_data_structures::sync::Lrc; use std::fmt; /// A SyntaxContext represents a chain of macro expansions (represented by marks). -#[derive(Clone, Copy, PartialEq, Eq, Default, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct SyntaxContext(u32); -#[derive(Copy, Clone, Debug)] +#[derive(Debug)] struct SyntaxContextData { outer_mark: Mark, transparency: Transparency, @@ -53,10 +53,10 @@ struct SyntaxContextData { } /// A mark is a unique ID associated with a macro expansion. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] pub struct Mark(u32); -#[derive(Clone, Debug)] +#[derive(Debug)] struct MarkData { parent: Mark, expn_info: Option, @@ -614,7 +614,7 @@ impl fmt::Debug for SyntaxContext { } /// Extra information for tracking spans of macro and syntax sugar expansion -#[derive(Clone, Hash, Debug, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct ExpnInfo { // --- The part unique to each expansion. /// The location of the actual macro invocation or syntax sugar , e.g. @@ -676,7 +676,7 @@ impl ExpnInfo { } /// The source of expansion. -#[derive(Clone, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] +#[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum ExpnKind { /// e.g., #[derive(...)] MacroAttribute(Symbol), @@ -724,7 +724,7 @@ impl MacroKind { } /// The kind of compiler desugaring. -#[derive(Clone, Copy, Hash, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)] +#[derive(Clone, Copy, PartialEq, Debug, RustcEncodable, RustcDecodable)] pub enum DesugaringKind { /// We desugar `if c { i } else { e }` to `match $ExprKind::Use(c) { true => i, _ => e }`. /// However, we do not want to blame `c` for unreachability but rather say that `i` -- cgit 1.4.1-3-g733a5 From aff9738462e8959c0a3eef57124b08d5f811cdec Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 30 Jun 2019 15:58:56 +0300 Subject: 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 f679a65c642..69e8c355019 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -408,8 +408,7 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind { - MacroAttribute(sym), - MacroBang(sym), + Macro(kind, descr), Desugaring(kind) }); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 9876d6c1fa5..3c8b0041a98 100644 --- a/src/librustc/lint/mod.rs +++ b/src/librustc/lint/mod.rs @@ -38,6 +38,7 @@ use syntax::ast; use syntax::source_map::{MultiSpan, ExpnKind, DesugaringKind}; use syntax::early_buffered_lints::BufferedEarlyLintId; use syntax::edition::Edition; +use syntax::ext::base::MacroKind; use syntax::symbol::{Symbol, sym}; use syntax_pos::Span; @@ -884,10 +885,9 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { }; match info.kind { - ExpnKind::MacroAttribute(..) => true, // definitely a plugin ExpnKind::Desugaring(DesugaringKind::ForLoop) => false, ExpnKind::Desugaring(_) => true, // well, it's "external" - ExpnKind::MacroBang(..) => { + ExpnKind::Macro(MacroKind::Bang, _) => { if info.def_site.is_dummy() { // dummy span for the def_site means it's an external macro return true; @@ -898,19 +898,16 @@ pub fn in_external_macro(sess: &Session, span: Span) -> bool { Err(_) => true, } } + ExpnKind::Macro(..) => true, // definitely a plugin } } /// Returns whether `span` originates in a derive macro's expansion pub fn in_derive_expansion(span: Span) -> bool { - let info = match span.ctxt().outer_expn_info() { - Some(info) => info, - // no ExpnInfo means this span doesn't come from a macro - None => return false, - }; - - match info.kind { - ExpnKind::MacroAttribute(symbol) => symbol.as_str().starts_with("derive("), - _ => false, + if let Some(info) = span.ctxt().outer_expn_info() { + if let ExpnKind::Macro(MacroKind::Derive, _) = info.kind { + return true; + } } + false } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index 18bbb257128..d0eefbb1179 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -11,7 +11,7 @@ use syntax::{ respan, ExpnInfo, ExpnKind, }, ext::{ - base::{ExtCtxt, Resolver}, + base::{ExtCtxt, MacroKind, Resolver}, build::AstBuilder, expand::ExpansionConfig, hygiene::{Mark, SyntaxContext}, @@ -87,7 +87,7 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { // Create a fresh Mark for the new macro expansion we are about to do let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(sym::global_allocator), item.span, self.sess.edition, + ExpnKind::Macro(MacroKind::Attr, sym::global_allocator), item.span, self.sess.edition, &[sym::rustc_attrs], )); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 61300e3ee3c..7f57b0a5052 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -114,17 +114,21 @@ fn sub_namespace_match(candidate: Option, requirement: Option String { - let mut path_str = String::with_capacity(64); - for (i, segment) in path.segments.iter().enumerate() { - if i != 0 { - path_str.push_str("::"); - } - if segment.ident.name != kw::PathRoot { - path_str.push_str(&segment.ident.as_str()) +fn fast_print_path(path: &ast::Path) -> Symbol { + if path.segments.len() == 1 { + return path.segments[0].ident.name + } else { + let mut path_str = String::with_capacity(64); + for (i, segment) in path.segments.iter().enumerate() { + if i != 0 { + path_str.push_str("::"); + } + if segment.ident.name != kw::PathRoot { + path_str.push_str(&segment.ident.as_str()) + } } + Symbol::intern(&path_str) } - path_str } impl<'a> base::Resolver for Resolver<'a> { @@ -219,14 +223,10 @@ impl<'a> base::Resolver for Resolver<'a> { }; let span = invoc.span(); - let path = fast_print_path(path); - let format = match kind { - MacroKind::Derive => format!("derive({})", path), - _ => path.clone(), - }; - invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, &format)); + let descr = fast_print_path(path); + invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, descr)); - self.check_stability_and_deprecation(&ext, &path, span); + self.check_stability_and_deprecation(&ext, descr, span); if let Res::Def(_, def_id) = res { if after_derive { @@ -991,7 +991,7 @@ impl<'a> Resolver<'a> { } } - fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &str, span: Span) { + fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, descr: Symbol, span: Span) { if let Some(stability) = &ext.stability { if let StabilityLevel::Unstable { reason, issue } = stability.level { let feature = stability.feature; @@ -1000,14 +1000,14 @@ impl<'a> Resolver<'a> { } } if let Some(depr) = &stability.rustc_depr { - let (message, lint) = stability::rustc_deprecation_message(depr, path); + let (message, lint) = stability::rustc_deprecation_message(depr, &descr.as_str()); stability::early_report_deprecation( self.session, &message, depr.suggestion, lint, span ); } } if let Some(depr) = &ext.deprecation { - let (message, lint) = stability::deprecation_message(depr, path); + let (message, lint) = stability::deprecation_message(depr, &descr.as_str()); stability::early_report_deprecation(self.session, &message, None, lint, span); } } diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index aeaee1887b9..2c8f7a44f5a 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -843,7 +843,8 @@ impl<'l, 'tcx> SaveContext<'l, 'tcx> { let callee = span.source_callee()?; // Ignore attribute macros, their spans are usually mangled - if let ExpnKind::MacroAttribute(_) = callee.kind { + if let ExpnKind::Macro(MacroKind::Attr, _) | + ExpnKind::Macro(MacroKind::Derive, _) = callee.kind { return None; } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 2f8d6f00ba7..04f124685cb 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -640,18 +640,10 @@ impl SyntaxExtension { } } - fn expn_kind(&self, descr: Symbol) -> ExpnKind { - match self.kind { - SyntaxExtensionKind::Bang(..) | - SyntaxExtensionKind::LegacyBang(..) => ExpnKind::MacroBang(descr), - _ => ExpnKind::MacroAttribute(descr), - } - } - - pub fn expn_info(&self, call_site: Span, descr: &str) -> ExpnInfo { + pub fn expn_info(&self, call_site: Span, descr: Symbol) -> ExpnInfo { ExpnInfo { call_site, - kind: self.expn_kind(Symbol::intern(descr)), + kind: ExpnKind::Macro(self.macro_kind(), descr), def_site: self.span, default_transparency: self.default_transparency, allow_internal_unstable: self.allow_internal_unstable.clone(), diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 24050be792b..68e7225c3cf 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 7ee073117e9..81f9ff9b661 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -1,7 +1,7 @@ use crate::ast; use crate::attr; use crate::edition::Edition; -use crate::ext::hygiene::{Mark, SyntaxContext}; +use crate::ext::hygiene::{Mark, SyntaxContext, MacroKind}; use crate::symbol::{Ident, Symbol, kw, sym}; use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan}; use crate::ptr::P; @@ -17,7 +17,8 @@ use syntax_pos::{DUMMY_SP, Span}; fn ignored_span(sp: Span, edition: Edition) -> Span { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(Symbol::intern("std_inject")), sp, edition, &[sym::prelude_import] + ExpnKind::Macro(MacroKind::Attr, Symbol::intern("std_inject")), sp, edition, + &[sym::prelude_import], )); sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) } diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 35a1a552a13..7ec7bb6ff45 100644 --- a/src/libsyntax/test.rs +++ b/src/libsyntax/test.rs @@ -21,7 +21,7 @@ use crate::entry::{self, EntryPointType}; use crate::ext::base::{ExtCtxt, Resolver}; use crate::ext::build::AstBuilder; use crate::ext::expand::ExpansionConfig; -use crate::ext::hygiene::{self, Mark, SyntaxContext}; +use crate::ext::hygiene::{self, Mark, SyntaxContext, MacroKind}; use crate::mut_visit::{*, ExpectOne}; use crate::feature_gate::Features; use crate::util::map_in_place::MapInPlace; @@ -280,7 +280,7 @@ fn generate_test_harness(sess: &ParseSess, }; mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(sym::test_case), DUMMY_SP, sess.edition, + ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, sess.edition, &[sym::main, sym::test, sym::rustc_attrs], )); diff --git a/src/libsyntax_ext/proc_macro_decls.rs b/src/libsyntax_ext/proc_macro_decls.rs index dee8f4b3eb5..0733a8ec95c 100644 --- a/src/libsyntax_ext/proc_macro_decls.rs +++ b/src/libsyntax_ext/proc_macro_decls.rs @@ -5,7 +5,7 @@ use crate::deriving; use syntax::ast::{self, Ident}; use syntax::attr; use syntax::source_map::{ExpnInfo, ExpnKind, respan}; -use syntax::ext::base::ExtCtxt; +use syntax::ext::base::{ExtCtxt, MacroKind}; use syntax::ext::build::AstBuilder; use syntax::ext::expand::ExpansionConfig; use syntax::ext::hygiene::Mark; @@ -348,7 +348,7 @@ fn mk_decls( ) -> P { let mark = Mark::fresh(Mark::root()); mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::MacroAttribute(sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, + ExpnKind::Macro(MacroKind::Attr, sym::proc_macro), DUMMY_SP, cx.parse_sess.edition, &[sym::rustc_attrs, Symbol::intern("proc_macro_internals")], )); let span = DUMMY_SP.apply_mark(mark); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 67dcdabe701..28d452233cc 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -135,11 +135,9 @@ impl Mark { pub fn looks_like_proc_macro_derive(self) -> bool { HygieneData::with(|data| { if data.default_transparency(self) == Transparency::Opaque { - if let Some(expn_info) = &data.marks[self.0 as usize].expn_info { - if let ExpnKind::MacroAttribute(name) = expn_info.kind { - if name.as_str().starts_with("derive(") { - return true; - } + if let Some(expn_info) = data.expn_info(self) { + if let ExpnKind::Macro(MacroKind::Derive, _) = expn_info.kind { + return true; } } } @@ -193,7 +191,7 @@ impl HygieneData { } fn default_transparency(&self, mark: Mark) -> Transparency { - self.marks[mark.0 as usize].expn_info.as_ref().map_or( + self.expn_info(mark).map_or( Transparency::SemiTransparent, |einfo| einfo.default_transparency ) } @@ -613,7 +611,8 @@ impl fmt::Debug for SyntaxContext { } } -/// Extra information for tracking spans of macro and syntax sugar expansion +/// A subset of properties from both macro definition and macro call available through global data. +/// Avoid using this if you have access to the original definition or call structures. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub struct ExpnInfo { // --- The part unique to each expansion. @@ -627,7 +626,7 @@ pub struct ExpnInfo { /// call_site span would have its own ExpnInfo, with the call_site /// pointing to the `foo!` invocation. pub call_site: Span, - /// The format with which the macro was invoked. + /// The kind of this expansion - macro or compiler desugaring. pub kind: ExpnKind, // --- The part specific to the macro/desugaring definition. @@ -675,13 +674,12 @@ impl ExpnInfo { } } -/// The source of expansion. +/// Expansion kind. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum ExpnKind { - /// e.g., #[derive(...)] - MacroAttribute(Symbol), - /// e.g., `format!()` - MacroBang(Symbol), + /// Expansion produced by a macro. + /// FIXME: Some code injected by the compiler before HIR lowering also gets this kind. + Macro(MacroKind, Symbol), /// Desugaring done by the compiler during HIR lowering. Desugaring(DesugaringKind) } @@ -689,8 +687,8 @@ pub enum ExpnKind { impl ExpnKind { pub fn descr(&self) -> Symbol { match *self { - ExpnKind::MacroBang(name) | ExpnKind::MacroAttribute(name) => name, - ExpnKind::Desugaring(kind) => kind.descr(), + ExpnKind::Macro(_, descr) => descr, + ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()), } } } @@ -743,8 +741,8 @@ pub enum DesugaringKind { } impl DesugaringKind { - pub fn descr(self) -> Symbol { - Symbol::intern(match self { + pub fn descr(self) -> &'static str { + match self { DesugaringKind::CondTemporary => "if and while condition", DesugaringKind::Async => "async", DesugaringKind::Await => "await", @@ -752,7 +750,7 @@ impl DesugaringKind { DesugaringKind::TryBlock => "try block", DesugaringKind::ExistentialType => "existential type", DesugaringKind::ForLoop => "for loop", - }) + } } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 1369fca3b4a..4fd27ce4f96 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -27,7 +27,7 @@ extern crate serialize as rustc_serialize; // used by deriving pub mod edition; use edition::Edition; pub mod hygiene; -pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnKind, DesugaringKind}; +pub use hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnKind, MacroKind, DesugaringKind}; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; @@ -442,9 +442,12 @@ impl Span { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { let (pre, post) = match info.kind { - ExpnKind::MacroAttribute(..) => ("#[", "]"), - ExpnKind::MacroBang(..) => ("", "!"), ExpnKind::Desugaring(..) => ("desugaring of `", "`"), + ExpnKind::Macro(macro_kind, _) => match macro_kind { + MacroKind::Bang => ("", "!"), + MacroKind::Attr => ("#[", "]"), + MacroKind::Derive => ("#[derive(", ")]"), + } }; result.push(MacroBacktrace { call_site: info.call_site, -- cgit 1.4.1-3-g733a5 From e2729460661c9bafb2e1862ddd0a63f75ae553e7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 2 Jul 2019 13:47:28 +0300 Subject: 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 41073773e9f..f946ca2903a 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -1,6 +1,5 @@ use crate::hir::map::definitions::*; -use crate::hir::def_id::{CRATE_DEF_INDEX, DefIndex}; -use crate::session::CrateDisambiguator; +use crate::hir::def_id::DefIndex; use syntax::ast::*; use syntax::ext::hygiene::Mark; @@ -14,31 +13,12 @@ pub struct DefCollector<'a> { definitions: &'a mut Definitions, parent_def: Option, expansion: Mark, - pub visit_macro_invoc: Option<&'a mut dyn FnMut(MacroInvocationData)>, -} - -pub struct MacroInvocationData { - pub mark: Mark, - pub def_index: DefIndex, } impl<'a> DefCollector<'a> { pub fn new(definitions: &'a mut Definitions, expansion: Mark) -> Self { - DefCollector { - definitions, - expansion, - parent_def: None, - visit_macro_invoc: None, - } - } - - pub fn collect_root(&mut self, - crate_name: &str, - crate_disambiguator: CrateDisambiguator) { - let root = self.definitions.create_root_def(crate_name, - crate_disambiguator); - assert_eq!(root, CRATE_DEF_INDEX); - self.parent_def = Some(root); + let parent_def = Some(definitions.invocation_parent(expansion)); + DefCollector { definitions, parent_def, expansion } } fn create_def(&mut self, @@ -97,12 +77,7 @@ impl<'a> DefCollector<'a> { } fn visit_macro_invoc(&mut self, id: NodeId) { - if let Some(ref mut visit) = self.visit_macro_invoc { - visit(MacroInvocationData { - mark: id.placeholder_to_mark(), - def_index: self.parent_def.unwrap(), - }) - } + self.definitions.set_invocation_parent(id.placeholder_to_mark(), self.parent_def.unwrap()); } } diff --git a/src/librustc/hir/map/definitions.rs b/src/librustc/hir/map/definitions.rs index 9e7898e10b0..9188a78e489 100644 --- a/src/librustc/hir/map/definitions.rs +++ b/src/librustc/hir/map/definitions.rs @@ -100,6 +100,9 @@ pub struct Definitions { expansions_that_defined: FxHashMap, next_disambiguator: FxHashMap<(DefIndex, DefPathData), u32>, def_index_to_span: FxHashMap, + /// When collecting definitions from an AST fragment produced by a macro invocation `Mark` + /// we know what parent node that fragment should be attached to thanks to this table. + invocation_parents: FxHashMap, } /// A unique identifier that we can use to lookup a definition @@ -434,6 +437,7 @@ impl Definitions { assert!(self.def_index_to_node.is_empty()); self.def_index_to_node.push(ast::CRATE_NODE_ID); self.node_to_def_index.insert(ast::CRATE_NODE_ID, root_index); + self.set_invocation_parent(Mark::root(), root_index); // Allocate some other DefIndices that always must exist. GlobalMetaDataKind::allocate_def_indices(self); @@ -526,6 +530,15 @@ impl Definitions { pub fn add_parent_module_of_macro_def(&mut self, mark: Mark, module: DefId) { self.parent_modules_of_macro_defs.insert(mark, module); } + + pub fn invocation_parent(&self, invoc_id: Mark) -> DefIndex { + self.invocation_parents[&invoc_id] + } + + pub fn set_invocation_parent(&mut self, invoc_id: Mark, parent: DefIndex) { + let old_parent = self.invocation_parents.insert(invoc_id, parent); + assert!(old_parent.is_none(), "parent def-index is reset for an invocation"); + } } impl DefPathData { diff --git a/src/librustc/hir/map/mod.rs b/src/librustc/hir/map/mod.rs index 63f60d0ab95..f9092196ab3 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 974487ab9d2..8515029193e 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 207b0b3754a..09d7d8ace6b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -19,7 +19,7 @@ use GenericParameters::*; use RibKind::*; use smallvec::smallvec; -use rustc::hir::map::{Definitions, DefCollector}; +use rustc::hir::map::Definitions; use rustc::hir::{self, PrimTy, Bool, Char, Float, Int, Uint, Str}; use rustc::middle::cstore::CrateStore; use rustc::session::Session; @@ -1901,8 +1901,7 @@ impl<'a> Resolver<'a> { module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root); let mut definitions = Definitions::default(); - DefCollector::new(&mut definitions, Mark::root()) - .collect_root(crate_name, session.local_crate_disambiguator()); + definitions.create_root_def(crate_name, session.local_crate_disambiguator()); let mut extern_prelude: FxHashMap> = session.opts.externs.iter().map(|kv| (Ident::from_str(kv.0), Default::default())) diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7f57b0a5052..8361bbe45c4 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -8,7 +8,7 @@ use crate::build_reduced_graph::{BuildReducedGraphVisitor, IsMacroExport}; use crate::resolve_imports::ImportResolver; use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX}; use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; -use rustc::hir::map::{self, DefCollector}; +use rustc::hir::map::DefCollector; use rustc::middle::stability; use rustc::{ty, lint, span_bug}; use syntax::ast::{self, Ident}; @@ -32,14 +32,14 @@ use rustc_data_structures::sync::Lrc; type Res = def::Res; +// FIXME: Merge this with `ParentScope`. #[derive(Clone, Debug)] pub struct InvocationData<'a> { - def_index: DefIndex, /// The module in which the macro was invoked. - crate module: Cell>, + crate module: Module<'a>, /// The legacy scope in which the macro was invoked. /// The invocation path is resolved in this scope. - crate parent_legacy_scope: Cell>, + crate parent_legacy_scope: LegacyScope<'a>, /// The legacy scope *produced* by expanding this macro invocation, /// includes all the macro_rules items, other invocations, etc generated by it. /// `None` if the macro is not expanded yet. @@ -49,10 +49,9 @@ pub struct InvocationData<'a> { impl<'a> InvocationData<'a> { pub fn root(graph_root: Module<'a>) -> Self { InvocationData { - module: Cell::new(graph_root), - def_index: CRATE_DEF_INDEX, - parent_legacy_scope: Cell::new(LegacyScope::Empty), - output_legacy_scope: Cell::new(Some(LegacyScope::Empty)), + module: graph_root, + parent_legacy_scope: LegacyScope::Empty, + output_legacy_scope: Cell::new(None), } } } @@ -74,9 +73,6 @@ pub struct LegacyBinding<'a> { /// can potentially expand into macro definitions. #[derive(Copy, Clone, Debug)] pub enum LegacyScope<'a> { - /// Created when invocation data is allocated in the arena; - /// must be replaced with a proper scope later. - Uninitialized, /// Empty "root" scope at the crate start containing no names. Empty, /// The scope introduced by a `macro_rules!` macro definition. @@ -139,11 +135,11 @@ impl<'a> base::Resolver for Resolver<'a> { fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { let mark = Mark::fresh(Mark::root()); let module = self.module_map[&self.definitions.local_def_id(id)]; + self.definitions.set_invocation_parent(mark, module.def_id().unwrap().index); self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData { - module: Cell::new(module), - def_index: module.def_id().unwrap().index, - parent_legacy_scope: Cell::new(LegacyScope::Empty), - output_legacy_scope: Cell::new(Some(LegacyScope::Empty)), + module, + parent_legacy_scope: LegacyScope::Empty, + output_legacy_scope: Cell::new(None), })); mark } @@ -160,16 +156,20 @@ impl<'a> base::Resolver for Resolver<'a> { fn visit_ast_fragment_with_placeholders(&mut self, mark: Mark, fragment: &AstFragment, derives: &[Mark]) { - let invocation = self.invocations[&mark]; - self.collect_def_ids(mark, invocation, fragment); + fragment.visit_with(&mut DefCollector::new(&mut self.definitions, mark)); - self.current_module = invocation.module.get(); + let invocation = self.invocations[&mark]; + self.current_module = invocation.module; self.current_module.unresolved_invocations.borrow_mut().remove(&mark); self.current_module.unresolved_invocations.borrow_mut().extend(derives); + let parent_def = self.definitions.invocation_parent(mark); + for &derive_invoc_id in derives { + self.definitions.set_invocation_parent(derive_invoc_id, parent_def); + } self.invocations.extend(derives.iter().map(|&derive| (derive, invocation))); let mut visitor = BuildReducedGraphVisitor { resolver: self, - current_legacy_scope: invocation.parent_legacy_scope.get(), + current_legacy_scope: invocation.parent_legacy_scope, expansion: mark, }; fragment.visit_with(&mut visitor); @@ -259,9 +259,9 @@ impl<'a> Resolver<'a> { fn invoc_parent_scope(&self, invoc_id: Mark, derives: Vec) -> ParentScope<'a> { let invoc = self.invocations[&invoc_id]; ParentScope { - module: invoc.module.get().nearest_item_scope(), + module: invoc.module.nearest_item_scope(), expansion: invoc_id.parent(), - legacy: invoc.parent_legacy_scope.get(), + legacy: invoc.parent_legacy_scope, derives, } } @@ -829,10 +829,9 @@ impl<'a> Resolver<'a> { binding.parent_legacy_scope ), LegacyScope::Invocation(invoc) => WhereToResolve::MacroRules( - invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope.get()) + invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope) ), LegacyScope::Empty => WhereToResolve::Module(parent_scope.module), - LegacyScope::Uninitialized => unreachable!(), } WhereToResolve::CrateRoot => match ns { TypeNS => { @@ -1084,31 +1083,6 @@ impl<'a> Resolver<'a> { } } - fn collect_def_ids(&mut self, - mark: Mark, - invocation: &'a InvocationData<'a>, - fragment: &AstFragment) { - let Resolver { ref mut invocations, arenas, graph_root, .. } = *self; - let InvocationData { def_index, .. } = *invocation; - - let visit_macro_invoc = &mut |invoc: map::MacroInvocationData| { - invocations.entry(invoc.mark).or_insert_with(|| { - arenas.alloc_invocation_data(InvocationData { - def_index: invoc.def_index, - module: Cell::new(graph_root), - parent_legacy_scope: Cell::new(LegacyScope::Uninitialized), - output_legacy_scope: Cell::new(None), - }) - }); - }; - - let mut def_collector = DefCollector::new(&mut self.definitions, mark); - def_collector.visit_macro_invoc = Some(visit_macro_invoc); - def_collector.with_parent(def_index, |def_collector| { - fragment.visit_with(def_collector) - }); - } - crate fn check_reserved_macro_name(&mut self, ident: Ident, res: Res) { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. -- cgit 1.4.1-3-g733a5 From b392781edc145d1d1592c6d1bba4c33fbc1f51d5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 2 Jul 2019 23:42:00 +0300 Subject: 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 f946ca2903a..6b93bd96a27 100644 --- a/src/librustc/hir/map/def_collector.rs +++ b/src/librustc/hir/map/def_collector.rs @@ -11,13 +11,13 @@ use syntax_pos::Span; /// Creates `DefId`s for nodes in the AST. pub struct DefCollector<'a> { definitions: &'a mut Definitions, - parent_def: Option, + parent_def: DefIndex, expansion: Mark, } impl<'a> DefCollector<'a> { pub fn new(definitions: &'a mut Definitions, expansion: Mark) -> Self { - let parent_def = Some(definitions.invocation_parent(expansion)); + let parent_def = definitions.invocation_parent(expansion); DefCollector { definitions, parent_def, expansion } } @@ -26,17 +26,15 @@ impl<'a> DefCollector<'a> { data: DefPathData, span: Span) -> DefIndex { - let parent_def = self.parent_def.unwrap(); + let parent_def = self.parent_def; debug!("create_def(node_id={:?}, data={:?}, parent_def={:?})", node_id, data, parent_def); - self.definitions - .create_def_with_parent(parent_def, node_id, data, self.expansion, span) + self.definitions.create_def_with_parent(parent_def, node_id, data, self.expansion, span) } pub fn with_parent(&mut self, parent_def: DefIndex, f: F) { - let parent = self.parent_def; - self.parent_def = Some(parent_def); + let orig_parent_def = std::mem::replace(&mut self.parent_def, parent_def); f(self); - self.parent_def = parent; + self.parent_def = orig_parent_def; } fn visit_async_fn( @@ -77,7 +75,7 @@ impl<'a> DefCollector<'a> { } fn visit_macro_invoc(&mut self, id: NodeId) { - self.definitions.set_invocation_parent(id.placeholder_to_mark(), self.parent_def.unwrap()); + self.definitions.set_invocation_parent(id.placeholder_to_mark(), self.parent_def); } } @@ -250,36 +248,24 @@ impl<'a> visit::Visitor<'a> for DefCollector<'a> { } fn visit_expr(&mut self, expr: &'a Expr) { - let parent_def = self.parent_def; - - match expr.node { + let parent_def = match expr.node { ExprKind::Mac(..) => return self.visit_macro_invoc(expr.id), ExprKind::Closure(_, asyncness, ..) => { - let closure_def = self.create_def(expr.id, - DefPathData::ClosureExpr, - expr.span); - self.parent_def = Some(closure_def); - // Async closures desugar to closures inside of closures, so // we must create two defs. - if let IsAsync::Async { closure_id, .. } = asyncness { - let async_def = self.create_def(closure_id, - DefPathData::ClosureExpr, - expr.span); - self.parent_def = Some(async_def); + let closure_def = self.create_def(expr.id, DefPathData::ClosureExpr, expr.span); + match asyncness { + IsAsync::Async { closure_id, .. } => + self.create_def(closure_id, DefPathData::ClosureExpr, expr.span), + IsAsync::NotAsync => closure_def, } } - ExprKind::Async(_, async_id, _) => { - let async_def = self.create_def(async_id, - DefPathData::ClosureExpr, - expr.span); - self.parent_def = Some(async_def); - } - _ => {} + ExprKind::Async(_, async_id, _) => + self.create_def(async_id, DefPathData::ClosureExpr, expr.span), + _ => self.parent_def, }; - visit::walk_expr(self, expr); - self.parent_def = parent_def; + self.with_parent(parent_def, |this| visit::walk_expr(this, expr)); } fn visit_ty(&mut self, ty: &'a Ty) { -- cgit 1.4.1-3-g733a5 From cd0fd630e8170f8770485cb8248ff3d823521523 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 01:44:04 +0300 Subject: 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 ++++++- .../ui/proc-macro/macro-namespace-reserved-2.rs | 10 +-- .../proc-macro/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 8515029193e..6fdd0c3ff3e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -46,20 +46,6 @@ use log::debug; type Res = def::Res; -fn proc_macro_stub(item: &Item) -> Option<(Ident, Span)> { - if attr::contains_name(&item.attrs, sym::proc_macro) || - attr::contains_name(&item.attrs, sym::proc_macro_attribute) { - return Some((item.ident, item.span)); - } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { - if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { - if let Some(ident) = nested_meta.ident() { - return Some((ident, ident.span)); - } - } - } - None -} - impl<'a> ToNameBinding<'a> for (Module<'a>, ty::Visibility, Span, Mark) { fn to_name_binding(self, arenas: &'a ResolverArenas<'a>) -> &'a NameBinding<'a> { arenas.alloc_name_binding(NameBinding { @@ -470,9 +456,7 @@ impl<'a> Resolver<'a> { // Functions introducing procedural macros reserve a slot // in the macro namespace as well (see #52225). - if let Some((ident, span)) = proc_macro_stub(item) { - self.define(parent, ident, MacroNS, (res, vis, span, expansion)); - } + self.define_macro(item, expansion, &mut LegacyScope::Empty); } // These items live in the type namespace. diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 09d7d8ace6b..b6c26b1a721 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -40,7 +40,7 @@ use rustc_metadata::cstore::CStore; use syntax::source_map::SourceMap; use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; -use syntax::ext::base::{SyntaxExtension, SyntaxExtensionKind}; +use syntax::ext::base::SyntaxExtension; use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::base::MacroKind; use syntax::symbol::{Symbol, kw, sym}; @@ -1663,10 +1663,13 @@ pub struct Resolver<'a> { macro_use_prelude: FxHashMap>, pub all_macros: FxHashMap, macro_map: FxHashMap>, + dummy_ext_bang: Lrc, + dummy_ext_derive: Lrc, non_macro_attrs: [Lrc; 2], macro_defs: FxHashMap, local_macro_def_scopes: FxHashMap>, unused_macros: NodeMap, + proc_macro_stubs: NodeSet, /// Maps the `Mark` of an expansion to its containing module or block. invocations: FxHashMap>, @@ -1925,9 +1928,8 @@ impl<'a> Resolver<'a> { macro_defs.insert(Mark::root(), root_def_id); let features = session.features_untracked(); - let non_macro_attr = |mark_used| Lrc::new(SyntaxExtension::default( - SyntaxExtensionKind::NonMacroAttr { mark_used }, session.edition() - )); + let non_macro_attr = + |mark_used| Lrc::new(SyntaxExtension::non_macro_attr(mark_used, session.edition())); Resolver { session, @@ -2002,6 +2004,8 @@ impl<'a> Resolver<'a> { macro_use_prelude: FxHashMap::default(), all_macros: FxHashMap::default(), macro_map: FxHashMap::default(), + dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())), + dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())), non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)], invocations, macro_defs, @@ -2010,6 +2014,7 @@ impl<'a> Resolver<'a> { potentially_unused_imports: Vec::new(), struct_constructors: Default::default(), unused_macros: Default::default(), + proc_macro_stubs: Default::default(), current_type_ascription: Vec::new(), injected_crate: None, active_features: @@ -2027,6 +2032,14 @@ impl<'a> Resolver<'a> { self.non_macro_attrs[mark_used as usize].clone() } + fn dummy_ext(&self, macro_kind: MacroKind) -> Lrc { + match macro_kind { + MacroKind::Bang => self.dummy_ext_bang.clone(), + MacroKind::Derive => self.dummy_ext_derive.clone(), + MacroKind::Attr => self.non_macro_attr(true), + } + } + /// Runs the function on each namespace. fn per_ns(&mut self, mut f: F) { f(self, TypeNS); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 8361bbe45c4..20eb97c15ba 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -11,7 +11,7 @@ use rustc::hir::def::{self, DefKind, NonMacroAttrKind}; use rustc::hir::map::DefCollector; use rustc::middle::stability; use rustc::{ty, lint, span_bug}; -use syntax::ast::{self, Ident}; +use syntax::ast::{self, Ident, ItemKind}; use syntax::attr::{self, StabilityLevel}; use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Determinacy}; @@ -127,6 +127,21 @@ fn fast_print_path(path: &ast::Path) -> Symbol { } } +fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> { + if attr::contains_name(&item.attrs, sym::proc_macro) { + return Some((MacroKind::Bang, item.ident, item.span)); + } else if attr::contains_name(&item.attrs, sym::proc_macro_attribute) { + return Some((MacroKind::Attr, item.ident, item.span)); + } else if let Some(attr) = attr::find_by_name(&item.attrs, sym::proc_macro_derive) { + if let Some(nested_meta) = attr.meta_item_list().and_then(|list| list.get(0).cloned()) { + if let Some(ident) = nested_meta.ident() { + return Some((MacroKind::Derive, ident, ident.span)); + } + } + } + None +} + impl<'a> base::Resolver for Resolver<'a> { fn next_node_id(&mut self) -> ast::NodeId { self.session.next_node_id() @@ -216,10 +231,9 @@ impl<'a> base::Resolver for Resolver<'a> { let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) { Ok((res, ext)) => (res, ext), - // Replace unresolved attributes with used inert attributes for better recovery. - Err(Determinacy::Determined) if kind == MacroKind::Attr => - (Res::Err, self.non_macro_attr(true)), - Err(determinacy) => return Err(determinacy), + // Return dummy syntax extensions for unresolved macros for better recovery. + Err(Determinacy::Determined) => (Res::Err, self.dummy_ext(kind)), + Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), }; let span = invoc.span(); @@ -305,13 +319,14 @@ impl<'a> Resolver<'a> { Res::Def(DefKind::Macro(_), def_id) => { if let Some(node_id) = self.definitions.as_local_node_id(def_id) { self.unused_macros.remove(&node_id); + if self.proc_macro_stubs.contains(&node_id) { + self.session.span_err( + path.span, + "can't use a procedural macro from the same crate that defines it", + ); + } } } - Res::Def(DefKind::Fn, _) => { - let msg = "can't use a procedural macro from the same crate that defines it"; - self.session.span_err(path.span, msg); - return Err(Determinacy::Determined); - } Res::NonMacroAttr(attr_kind) => { if kind == MacroKind::Attr { if attr_kind == NonMacroAttrKind::Custom { @@ -1100,19 +1115,32 @@ impl<'a> Resolver<'a> { item: &ast::Item, expansion: Mark, current_legacy_scope: &mut LegacyScope<'a>) { - self.local_macro_def_scopes.insert(item.id, self.current_module); - let ident = item.ident; + let (ext, ident, span, is_legacy) = match &item.node { + ItemKind::MacroDef(def) => { + let ext = Lrc::new(macro_rules::compile( + &self.session.parse_sess, + &self.session.features_untracked(), + item, + self.session.edition(), + )); + (ext, item.ident, item.span, def.legacy) + } + ItemKind::Fn(..) => match proc_macro_stub(item) { + Some((macro_kind, ident, span)) => { + self.proc_macro_stubs.insert(item.id); + (self.dummy_ext(macro_kind), ident, span, false) + } + None => return, + } + _ => unreachable!(), + }; let def_id = self.definitions.local_def_id(item.id); - let ext = Lrc::new(macro_rules::compile(&self.session.parse_sess, - &self.session.features_untracked(), - item, self.session.edition())); - let macro_kind = ext.macro_kind(); - let res = Res::Def(DefKind::Macro(macro_kind), def_id); + let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id); self.macro_map.insert(def_id, ext); + self.local_macro_def_scopes.insert(item.id, self.current_module); - let def = match item.node { ast::ItemKind::MacroDef(ref def) => def, _ => unreachable!() }; - if def.legacy { + if is_legacy { let ident = ident.modern(); self.macro_names.insert(ident); let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export); @@ -1121,7 +1149,7 @@ impl<'a> Resolver<'a> { } else { ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)) }; - let binding = (res, vis, item.span, expansion).to_name_binding(self.arenas); + let binding = (res, vis, span, expansion).to_name_binding(self.arenas); self.set_binding_parent_module(binding, self.current_module); let legacy_binding = self.arenas.alloc_legacy_binding(LegacyBinding { parent_legacy_scope: *current_legacy_scope, binding, ident @@ -1131,18 +1159,18 @@ impl<'a> Resolver<'a> { if is_macro_export { let module = self.graph_root; self.define(module, ident, MacroNS, - (res, vis, item.span, expansion, IsMacroExport)); + (res, vis, span, expansion, IsMacroExport)); } else { self.check_reserved_macro_name(ident, res); - self.unused_macros.insert(item.id, item.span); + self.unused_macros.insert(item.id, span); } } else { let module = self.current_module; let vis = self.resolve_visibility(&item.vis); if vis != ty::Visibility::Public { - self.unused_macros.insert(item.id, item.span); + self.unused_macros.insert(item.id, span); } - self.define(module, ident, MacroNS, (res, vis, item.span, expansion)); + self.define(module, ident, MacroNS, (res, vis, span, expansion)); } } } diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 04f124685cb..82386b78f1d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -10,7 +10,7 @@ use crate::parse::token; use crate::ptr::P; use crate::symbol::{kw, sym, Ident, Symbol}; use crate::{ThinVec, MACRO_ARGUMENTS}; -use crate::tokenstream::{self, TokenStream}; +use crate::tokenstream::{self, TokenStream, TokenTree}; use errors::{DiagnosticBuilder, DiagnosticId}; use smallvec::{smallvec, SmallVec}; @@ -640,6 +640,26 @@ impl SyntaxExtension { } } + pub fn dummy_bang(edition: Edition) -> SyntaxExtension { + fn expander<'cx>(_: &'cx mut ExtCtxt<'_>, span: Span, _: &[TokenTree]) + -> Box { + DummyResult::any(span) + } + SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition) + } + + pub fn dummy_derive(edition: Edition) -> SyntaxExtension { + fn expander(_: &mut ExtCtxt<'_>, _: Span, _: &ast::MetaItem, _: Annotatable) + -> Vec { + Vec::new() + } + SyntaxExtension::default(SyntaxExtensionKind::Derive(Box::new(expander)), edition) + } + + pub fn non_macro_attr(mark_used: bool, edition: Edition) -> SyntaxExtension { + SyntaxExtension::default(SyntaxExtensionKind::NonMacroAttr { mark_used }, edition) + } + pub fn expn_info(&self, call_site: Span, descr: Symbol) -> ExpnInfo { ExpnInfo { call_site, diff --git a/src/test/ui/proc-macro/macro-namespace-reserved-2.rs b/src/test/ui/proc-macro/macro-namespace-reserved-2.rs index 583640aa817..c7b092830a2 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 548f9e3051d..83c77513ec3 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`. -- cgit 1.4.1-3-g733a5 From f16993d4acaf90285f6c86268a0ec2e7167c2a58 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 11:44:57 +0300 Subject: resolve/expand: `resolve_macro_invocation` no longer returns determinate errors It either returns the indeterminacy error, or valid (but perhaps dummy) `SyntaxExtension`. With this change enum `Determinacy` is no longer used in libsyntax and can be moved to resolve. The regressions in diagnosics are fixed in the next commits. --- src/librustc_resolve/build_reduced_graph.rs | 9 +- src/librustc_resolve/lib.rs | 14 ++- src/librustc_resolve/macros.rs | 66 +++++------- src/librustc_resolve/resolve_imports.rs | 2 +- src/libsyntax/ext/base.rs | 17 +--- src/libsyntax/ext/expand.rs | 111 ++++++++++----------- src/test/ui/macros/macro-path-prelude-fail-4.rs | 2 +- .../ui/macros/macro-path-prelude-fail-4.stderr | 2 +- .../tool-attributes/tool-attributes-misplaced-2.rs | 4 +- .../tool-attributes-misplaced-2.stderr | 4 +- 10 files changed, 108 insertions(+), 123 deletions(-) diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 6fdd0c3ff3e..f74d07a3c5e 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -9,7 +9,7 @@ use crate::resolve_imports::ImportDirectiveSubclass::{self, GlobImport, SingleIm use crate::{Module, ModuleData, ModuleKind, NameBinding, NameBindingKind, Segment, ToNameBinding}; use crate::{ModuleOrUniformRoot, PerNS, Resolver, ResolverArenas, ExternPreludeEntry}; use crate::Namespace::{self, TypeNS, ValueNS, MacroNS}; -use crate::{resolve_error, resolve_struct_error, ResolutionError}; +use crate::{resolve_error, resolve_struct_error, ResolutionError, Determinacy}; use rustc::bug; use rustc::hir::def::{self, *}; @@ -30,7 +30,6 @@ use syntax::attr; use syntax::ast::{self, Block, ForeignItem, ForeignItemKind, Item, ItemKind, NodeId}; use syntax::ast::{MetaItemKind, StmtKind, TraitItem, TraitItemKind, Variant}; use syntax::ext::base::SyntaxExtension; -use syntax::ext::base::Determinacy::Undetermined; use syntax::ext::hygiene::Mark; use syntax::ext::tt::macro_rules; use syntax::feature_gate::is_builtin_attr; @@ -231,9 +230,9 @@ impl<'a> Resolver<'a> { source: source.ident, target: ident, source_bindings: PerNS { - type_ns: Cell::new(Err(Undetermined)), - value_ns: Cell::new(Err(Undetermined)), - macro_ns: Cell::new(Err(Undetermined)), + type_ns: Cell::new(Err(Determinacy::Undetermined)), + value_ns: Cell::new(Err(Determinacy::Undetermined)), + macro_ns: Cell::new(Err(Determinacy::Undetermined)), }, target_bindings: PerNS { type_ns: Cell::new(None), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index b6c26b1a721..795ff3faffa 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -15,6 +15,7 @@ pub use rustc::hir::def::{Namespace, PerNS}; +use Determinacy::*; use GenericParameters::*; use RibKind::*; use smallvec::smallvec; @@ -41,7 +42,6 @@ use syntax::source_map::SourceMap; use syntax::ext::hygiene::{Mark, Transparency, SyntaxContext}; use syntax::ast::{self, Name, NodeId, Ident, FloatTy, IntTy, UintTy}; use syntax::ext::base::SyntaxExtension; -use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::base::MacroKind; use syntax::symbol::{Symbol, kw, sym}; use syntax::util::lev_distance::find_best_match_for_name; @@ -93,6 +93,18 @@ enum Weak { No, } +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum Determinacy { + Determined, + Undetermined, +} + +impl Determinacy { + fn determined(determined: bool) -> Determinacy { + if determined { Determinacy::Determined } else { Determinacy::Undetermined } + } +} + enum ScopeSet { Import(Namespace), AbsolutePath(Namespace), diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 20eb97c15ba..905b3347a54 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -1,4 +1,4 @@ -use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc}; +use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc, Determinacy}; use crate::{CrateLint, Resolver, ResolutionError, ScopeSet, Weak}; use crate::{Module, ModuleKind, NameBinding, NameBindingKind, PathResult, Segment, ToNameBinding}; use crate::{is_known_tool, resolve_error}; @@ -14,7 +14,7 @@ use rustc::{ty, lint, span_bug}; use syntax::ast::{self, Ident, ItemKind}; use syntax::attr::{self, StabilityLevel}; use syntax::errors::DiagnosticBuilder; -use syntax::ext::base::{self, Determinacy}; +use syntax::ext::base::{self, Indeterminate}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; use syntax::ext::hygiene::{self, Mark}; @@ -216,7 +216,7 @@ impl<'a> base::Resolver for Resolver<'a> { } fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) - -> Result>, Determinacy> { + -> Result>, Indeterminate> { let (path, kind, derives_in_scope, after_derive) = match invoc.kind { InvocationKind::Attr { attr: None, .. } => return Ok(None), @@ -229,12 +229,7 @@ impl<'a> base::Resolver for Resolver<'a> { }; let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - let (res, ext) = match self.resolve_macro_to_res(path, kind, &parent_scope, true, force) { - Ok((res, ext)) => (res, ext), - // Return dummy syntax extensions for unresolved macros for better recovery. - Err(Determinacy::Determined) => (Res::Err, self.dummy_ext(kind)), - Err(Determinacy::Undetermined) => return Err(Determinacy::Undetermined), - }; + let (res, ext) = self.resolve_macro_to_res(path, kind, &parent_scope, true, force)?; let span = invoc.span(); let descr = fast_print_path(path); @@ -287,7 +282,7 @@ impl<'a> Resolver<'a> { parent_scope: &ParentScope<'a>, trace: bool, force: bool, - ) -> Result<(Res, Lrc), Determinacy> { + ) -> Result<(Res, Lrc), Indeterminate> { let res = self.resolve_macro_to_res_inner(path, kind, parent_scope, trace, force); // Report errors and enforce feature gates for the resolved macro. @@ -313,7 +308,14 @@ impl<'a> Resolver<'a> { } } - let res = res?; + let res = match res { + Err(Determinacy::Undetermined) => return Err(Indeterminate), + Ok(Res::Err) | Err(Determinacy::Determined) => { + // Return dummy syntax extensions for unresolved macros for better recovery. + return Ok((Res::Err, self.dummy_ext(kind))); + } + Ok(res) => res, + }; match res { Res::Def(DefKind::Macro(_), def_id) => { @@ -328,35 +330,23 @@ impl<'a> Resolver<'a> { } } Res::NonMacroAttr(attr_kind) => { - if kind == MacroKind::Attr { - if attr_kind == NonMacroAttrKind::Custom { - assert!(path.segments.len() == 1); - if !features.custom_attribute { - let msg = format!("The attribute `{}` is currently unknown to the \ - compiler and may have meaning added to it in the \ - future", path); - self.report_unknown_attribute( - path.span, - &path.segments[0].ident.as_str(), - &msg, - sym::custom_attribute, - ); - } + if attr_kind == NonMacroAttrKind::Custom { + assert!(path.segments.len() == 1); + if !features.custom_attribute { + let msg = format!("The attribute `{}` is currently unknown to the \ + compiler and may have meaning added to it in the \ + future", path); + self.report_unknown_attribute( + path.span, + &path.segments[0].ident.as_str(), + &msg, + sym::custom_attribute, + ); } - } else { - // Not only attributes, but anything in macro namespace can result in - // `Res::NonMacroAttr` definition (e.g., `inline!()`), so we must report - // an error for those cases. - let msg = format!("expected a macro, found {}", res.descr()); - self.session.span_err(path.span, &msg); - return Err(Determinacy::Determined); } } - Res::Err => { - return Err(Determinacy::Determined); - } _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), - } + }; Ok((res, self.get_macro(res))) } @@ -608,9 +598,7 @@ impl<'a> Resolver<'a> { result = Ok((binding, Flags::empty())); break; } - Err(Determinacy::Determined) => {} - Err(Determinacy::Undetermined) => - result = Err(Determinacy::Undetermined), + Err(Indeterminate) => result = Err(Determinacy::Undetermined), } } result diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 7de1cd29a9c..5edfe923e68 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -2,6 +2,7 @@ use ImportDirectiveSubclass::*; use crate::{AmbiguityError, AmbiguityKind, AmbiguityErrorMisc}; use crate::{CrateLint, Module, ModuleOrUniformRoot, PerNS, ScopeSet, Weak}; +use crate::Determinacy::{self, *}; use crate::Namespace::{self, TypeNS, MacroNS}; use crate::{NameBinding, NameBindingKind, ToNameBinding, PathResult, PrivacyError}; use crate::{Resolver, Segment}; @@ -27,7 +28,6 @@ use rustc::util::nodemap::FxHashSet; use rustc::{bug, span_bug}; use syntax::ast::{self, Ident, Name, NodeId, CRATE_NODE_ID}; -use syntax::ext::base::Determinacy::{self, Determined, Undetermined}; use syntax::ext::hygiene::Mark; use syntax::symbol::kw; use syntax::util::lev_distance::find_best_match_for_name; diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index 82386b78f1d..cb4edee30cd 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -676,6 +676,9 @@ impl SyntaxExtension { pub type NamedSyntaxExtension = (Name, SyntaxExtension); +/// Error type that denotes indeterminacy. +pub struct Indeterminate; + pub trait Resolver { fn next_node_id(&mut self) -> ast::NodeId; @@ -689,23 +692,11 @@ pub trait Resolver { fn resolve_imports(&mut self); fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) - -> Result>, Determinacy>; + -> Result>, Indeterminate>; fn check_unused_macros(&self); } -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum Determinacy { - Determined, - Undetermined, -} - -impl Determinacy { - pub fn determined(determined: bool) -> Determinacy { - if determined { Determinacy::Determined } else { Determinacy::Undetermined } - } -} - #[derive(Clone)] pub struct ModuleData { pub mod_path: Vec, diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 06ff2bc655c..2f7fb79a7f5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -313,9 +313,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let scope = if self.monotonic { invoc.expansion_data.mark } else { orig_expansion_data.mark }; let ext = match self.cx.resolver.resolve_macro_invocation(&invoc, scope, force) { - Ok(ext) => Some(ext), - Err(Determinacy::Determined) => None, - Err(Determinacy::Undetermined) => { + Ok(ext) => ext, + Err(Indeterminate) => { undetermined_invocations.push(invoc); continue } @@ -328,65 +327,61 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.current_expansion.mark = scope; // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { - if let Some(ext) = ext { - let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); - let fragment = self.expand_invoc(invoc, &*ext).unwrap_or_else(|| { - invoc_fragment_kind.dummy(invoc_span).unwrap() - }); - self.collect_invocations(fragment, &[]) - } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { - if !item.derive_allowed() { - let attr = attr::find_by_name(item.attrs(), sym::derive) - .expect("`derive` attribute should exist"); - let span = attr.span; - let mut err = self.cx.mut_span_err(span, - "`derive` may only be applied to \ - structs, enums and unions"); - if let ast::AttrStyle::Inner = attr.style { - let trait_list = traits.iter() - .map(|t| t.to_string()).collect::>(); - let suggestion = format!("#[derive({})]", trait_list.join(", ")); - err.span_suggestion( - span, "try an outer attribute", suggestion, - // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT - Applicability::MaybeIncorrect - ); - } - err.emit(); + let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); + let fragment = self.expand_invoc(invoc, &*ext).unwrap_or_else(|| { + invoc_fragment_kind.dummy(invoc_span).unwrap() + }); + self.collect_invocations(fragment, &[]) + } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { + if !item.derive_allowed() { + let attr = attr::find_by_name(item.attrs(), sym::derive) + .expect("`derive` attribute should exist"); + let span = attr.span; + let mut err = self.cx.mut_span_err(span, + "`derive` may only be applied to \ + structs, enums and unions"); + if let ast::AttrStyle::Inner = attr.style { + let trait_list = traits.iter() + .map(|t| t.to_string()).collect::>(); + let suggestion = format!("#[derive({})]", trait_list.join(", ")); + err.span_suggestion( + span, "try an outer attribute", suggestion, + // We don't 𝑘𝑛𝑜𝑤 that the following item is an ADT + Applicability::MaybeIncorrect + ); } + err.emit(); + } - let mut item = self.fully_configure(item); - item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); - let mut item_with_markers = item.clone(); - add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers); - let derives = derives.entry(invoc.expansion_data.mark).or_default(); - - derives.reserve(traits.len()); - invocations.reserve(traits.len()); - for path in traits { - let mark = Mark::fresh(self.cx.current_expansion.mark); - derives.push(mark); - invocations.push(Invocation { - kind: InvocationKind::Derive { - path, - item: item.clone(), - item_with_markers: item_with_markers.clone(), - }, - fragment_kind: invoc.fragment_kind, - expansion_data: ExpansionData { - mark, - ..invoc.expansion_data.clone() - }, - }); - } - let fragment = invoc.fragment_kind - .expect_from_annotatables(::std::iter::once(item_with_markers)); - self.collect_invocations(fragment, derives) - } else { - unreachable!() + let mut item = self.fully_configure(item); + item.visit_attrs(|attrs| attrs.retain(|a| a.path != sym::derive)); + let mut item_with_markers = item.clone(); + add_derived_markers(&mut self.cx, item.span(), &traits, &mut item_with_markers); + let derives = derives.entry(invoc.expansion_data.mark).or_default(); + + derives.reserve(traits.len()); + invocations.reserve(traits.len()); + for path in traits { + let mark = Mark::fresh(self.cx.current_expansion.mark); + derives.push(mark); + invocations.push(Invocation { + kind: InvocationKind::Derive { + path, + item: item.clone(), + item_with_markers: item_with_markers.clone(), + }, + fragment_kind: invoc.fragment_kind, + expansion_data: ExpansionData { + mark, + ..invoc.expansion_data.clone() + }, + }); } + let fragment = invoc.fragment_kind + .expect_from_annotatables(::std::iter::once(item_with_markers)); + self.collect_invocations(fragment, derives) } else { - self.collect_invocations(invoc.fragment_kind.dummy(invoc.span()).unwrap(), &[]) + unreachable!() }; if expanded_fragments.len() < depth { diff --git a/src/test/ui/macros/macro-path-prelude-fail-4.rs b/src/test/ui/macros/macro-path-prelude-fail-4.rs index 283427b9ace..44f0f2d7ec0 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 f08445e1f77..fdd7bf3235c 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 56b908d94cc..b95791f4e99 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 c5f5f59c32c..8ef27a07b7f 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!(); -- cgit 1.4.1-3-g733a5 From 3041ec61185d6f9795ff16cc345e8f11b06edbbf Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 12:47:24 +0300 Subject: 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 ++--------- .../ui/feature-gates/feature-gate-rustc-attrs.rs | 4 +- .../feature-gates/feature-gate-rustc-attrs.stderr | 12 ++-- src/test/ui/macros/macro-path-prelude-fail-4.rs | 2 +- .../ui/macros/macro-path-prelude-fail-4.stderr | 4 +- .../ui/proc-macro/macro-namespace-reserved-2.rs | 12 +++- .../proc-macro/macro-namespace-reserved-2.stderr | 76 ++++++++++++++++++---- .../tool-attributes/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 905b3347a54..30969948c4c 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -348,7 +348,18 @@ impl<'a> Resolver<'a> { _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), }; - Ok((res, self.get_macro(res))) + let ext = self.get_macro(res); + Ok(if ext.macro_kind() != kind { + let expected = if kind == MacroKind::Attr { "attribute" } else { kind.descr() }; + let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path); + self.session.struct_span_err(path.span, &msg) + .span_label(path.span, format!("not {} {}", kind.article(), expected)) + .emit(); + // Return dummy syntax extensions for unexpected macro kinds for better recovery. + (Res::Err, self.dummy_ext(kind)) + } else { + (res, ext) + }) } fn report_unknown_attribute(&self, span: Span, name: &str, msg: &str, feature: Symbol) { diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 2f7fb79a7f5..2349382eb5e 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -323,12 +323,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { progress = true; let ExpansionData { depth, mark, .. } = invoc.expansion_data; self.cx.current_expansion = invoc.expansion_data.clone(); - self.cx.current_expansion.mark = scope; + // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); - let fragment = self.expand_invoc(invoc, &*ext).unwrap_or_else(|| { + let fragment = self.expand_invoc(invoc, &ext).unwrap_or_else(|| { invoc_fragment_kind.dummy(invoc_span).unwrap() }); self.collect_invocations(fragment, &[]) @@ -551,17 +551,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.gate_proc_macro_expansion(attr.span, &res); res } - SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => { - self.cx.span_err(attr.span, &format!("`{}` is a derive macro", attr.path)); - self.cx.trace_macros_diag(); - invoc.fragment_kind.dummy(attr.span) - } - _ => { - let msg = &format!("macro `{}` may not be used in attributes", attr.path); - self.cx.span_err(attr.span, msg); - self.cx.trace_macros_diag(); - invoc.fragment_kind.dummy(attr.span) - } + _ => unreachable!() } } @@ -671,21 +661,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let tok_result = expander.expand(self.cx, span, mac.node.stream()); kind.make_from(tok_result) } - - SyntaxExtensionKind::Attr(..) | - SyntaxExtensionKind::LegacyAttr(..) | - SyntaxExtensionKind::NonMacroAttr { .. } => { - self.cx.span_err(path.span, - &format!("`{}` can only be used in attributes", path)); - self.cx.trace_macros_diag(); - kind.dummy(span) - } - - SyntaxExtensionKind::Derive(..) | SyntaxExtensionKind::LegacyDerive(..) => { - self.cx.span_err(path.span, &format!("`{}` is a derive macro", path)); - self.cx.trace_macros_diag(); - kind.dummy(span) - } + _ => unreachable!() }; if opt_expanded.is_some() { @@ -747,12 +723,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let items = expander.expand(self.cx, span, &meta, item); Some(invoc.fragment_kind.expect_from_annotatables(items)) } - _ => { - let msg = &format!("macro `{}` may not be used for derive attributes", path); - self.cx.span_err(path.span, msg); - self.cx.trace_macros_diag(); - invoc.fragment_kind.dummy(path.span) - } + _ => unreachable!() } } diff --git a/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs b/src/test/ui/feature-gates/feature-gate-rustc-attrs.rs index d3a2e486416..9ce2fb58ab0 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 f098635c702..7c5aa5381e8 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 44f0f2d7ec0..0f93fcdaa5f 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 fdd7bf3235c..dfd6818b678 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 c7b092830a2..7a9e472c6c3 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 83c77513ec3..a724d388f48 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 b95791f4e99..b5666e4ea70 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 8ef27a07b7f..6d0f826e621 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 -- cgit 1.4.1-3-g733a5 From 8bc187d1047b3680efe2cda53dcc83f45012578b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 23:25:46 +0300 Subject: 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 30969948c4c..7cb33ca3ed4 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -867,7 +867,7 @@ impl<'a> Resolver<'a> { } } } - WhereToResolve::MacroUsePrelude => WhereToResolve::BuiltinMacros, + WhereToResolve::MacroUsePrelude => WhereToResolve::StdLibPrelude, WhereToResolve::BuiltinMacros => WhereToResolve::BuiltinAttrs, WhereToResolve::BuiltinAttrs => WhereToResolve::LegacyPluginHelpers, WhereToResolve::LegacyPluginHelpers => break, // nowhere else to search @@ -877,7 +877,7 @@ impl<'a> Resolver<'a> { WhereToResolve::StdLibPrelude => match ns { TypeNS => WhereToResolve::BuiltinTypes, ValueNS => break, // nowhere else to search - MacroNS => unreachable!(), + MacroNS => WhereToResolve::BuiltinMacros, } WhereToResolve::BuiltinTypes => break, // nowhere else to search }; -- cgit 1.4.1-3-g733a5 From f92394209455bf14594f279249c2e592809180cd Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 3 Jul 2019 23:59:03 +0300 Subject: 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 ++++++++++----------- src/librustdoc/passes/collect_intra_doc_links.rs | 4 +- src/test/ui/feature-gates/feature-gate-asm.stderr | 2 +- src/test/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-gates/feature-gate-global_asm.stderr | 2 +- .../feature-gates/feature-gate-log_syntax.stderr | 2 +- .../feature-gates/feature-gate-log_syntax2.stderr | 2 +- .../feature-gates/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 f74d07a3c5e..16fd8cccc89 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -755,11 +755,7 @@ impl<'a> Resolver<'a> { } } - pub fn get_macro(&mut self, res: Res) -> Lrc { - self.opt_get_macro(res).expect("expected `DefKind::Macro` or `Res::NonMacroAttr`") - } - - crate fn opt_get_macro(&mut self, res: Res) -> Option> { + pub fn get_macro(&mut self, res: Res) -> Option> { let def_id = match res { Res::Def(DefKind::Macro(..), def_id) => def_id, Res::NonMacroAttr(attr_kind) => diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7cb33ca3ed4..077c126bdee 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -229,13 +229,10 @@ impl<'a> base::Resolver for Resolver<'a> { }; let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); - let (res, ext) = self.resolve_macro_to_res(path, kind, &parent_scope, true, force)?; + let (ext, res) = self.smart_resolve_macro_path(path, kind, &parent_scope, true, force)?; let span = invoc.span(); - let descr = fast_print_path(path); - invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, descr)); - - self.check_stability_and_deprecation(&ext, descr, span); + invoc.expansion_data.mark.set_expn_info(ext.expn_info(span, fast_print_path(path))); if let Res::Def(_, def_id) = res { if after_derive { @@ -275,47 +272,42 @@ impl<'a> Resolver<'a> { } } - fn resolve_macro_to_res( + /// Resolve macro path with error reporting and recovery. + fn smart_resolve_macro_path( &mut self, path: &ast::Path, kind: MacroKind, parent_scope: &ParentScope<'a>, trace: bool, force: bool, - ) -> Result<(Res, Lrc), Indeterminate> { - let res = self.resolve_macro_to_res_inner(path, kind, parent_scope, trace, force); + ) -> Result<(Lrc, Res), Indeterminate> { + let (ext, res) = match self.resolve_macro_path(path, kind, parent_scope, trace, force) { + Ok((Some(ext), res)) => (ext, res), + // Use dummy syntax extensions for unresolved macros for better recovery. + Ok((None, res)) => (self.dummy_ext(kind), res), + Err(Determinacy::Determined) => (self.dummy_ext(kind), Res::Err), + Err(Determinacy::Undetermined) => return Err(Indeterminate), + }; // Report errors and enforce feature gates for the resolved macro. let features = self.session.features_untracked(); - if res != Err(Determinacy::Undetermined) { - // Do not report duplicated errors on every undetermined resolution. - for segment in &path.segments { - if let Some(args) = &segment.args { - self.session.span_err(args.span(), "generic arguments in macro path"); - } - if kind == MacroKind::Attr && !features.rustc_attrs && - segment.ident.as_str().starts_with("rustc") { - let msg = "attributes starting with `rustc` are \ - reserved for use by the `rustc` compiler"; - emit_feature_err( - &self.session.parse_sess, - sym::rustc_attrs, - segment.ident.span, - GateIssue::Language, - msg, - ); - } + for segment in &path.segments { + if let Some(args) = &segment.args { + self.session.span_err(args.span(), "generic arguments in macro path"); } - } - - let res = match res { - Err(Determinacy::Undetermined) => return Err(Indeterminate), - Ok(Res::Err) | Err(Determinacy::Determined) => { - // Return dummy syntax extensions for unresolved macros for better recovery. - return Ok((Res::Err, self.dummy_ext(kind))); + if kind == MacroKind::Attr && !features.rustc_attrs && + segment.ident.as_str().starts_with("rustc") { + let msg = + "attributes starting with `rustc` are reserved for use by the `rustc` compiler"; + emit_feature_err( + &self.session.parse_sess, + sym::rustc_attrs, + segment.ident.span, + GateIssue::Language, + msg, + ); } - Ok(res) => res, - }; + } match res { Res::Def(DefKind::Macro(_), def_id) => { @@ -345,20 +337,22 @@ impl<'a> Resolver<'a> { } } } + Res::Err => {} _ => panic!("expected `DefKind::Macro` or `Res::NonMacroAttr`"), }; - let ext = self.get_macro(res); + self.check_stability_and_deprecation(&ext, path); + Ok(if ext.macro_kind() != kind { let expected = if kind == MacroKind::Attr { "attribute" } else { kind.descr() }; let msg = format!("expected {}, found {} `{}`", expected, res.descr(), path); self.session.struct_span_err(path.span, &msg) .span_label(path.span, format!("not {} {}", kind.article(), expected)) .emit(); - // Return dummy syntax extensions for unexpected macro kinds for better recovery. - (Res::Err, self.dummy_ext(kind)) + // Use dummy syntax extensions for unexpected macro kinds for better recovery. + (self.dummy_ext(kind), Res::Err) } else { - (res, ext) + (ext, res) }) } @@ -416,14 +410,14 @@ impl<'a> Resolver<'a> { err.emit(); } - pub fn resolve_macro_to_res_inner( + pub fn resolve_macro_path( &mut self, path: &ast::Path, kind: MacroKind, parent_scope: &ParentScope<'a>, trace: bool, force: bool, - ) -> Result { + ) -> Result<(Option>, Res), Determinacy> { let path_span = path.span; let mut path = Segment::from_path(path); @@ -435,7 +429,7 @@ impl<'a> Resolver<'a> { path.insert(0, Segment::from_ident(root)); } - if path.len() > 1 { + let res = if path.len() > 1 { let res = match self.resolve_path(&path, Some(MacroNS), parent_scope, false, path_span, CrateLint::No) { PathResult::NonModule(path_res) if path_res.unresolved_segments() == 0 => { @@ -471,7 +465,9 @@ impl<'a> Resolver<'a> { let res = binding.map(|binding| binding.res()); self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); res - } + }; + + res.map(|res| (self.get_macro(res), res)) } // Resolve an identifier in lexical scope. @@ -600,16 +596,18 @@ impl<'a> Resolver<'a> { let mut result = Err(Determinacy::Determined); for derive in &parent_scope.derives { let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope }; - match self.resolve_macro_to_res(derive, MacroKind::Derive, - &parent_scope, true, force) { - Ok((_, ext)) => if ext.helper_attrs.contains(&ident.name) { + match self.resolve_macro_path(derive, MacroKind::Derive, + &parent_scope, true, force) { + Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) { let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper), ty::Visibility::Public, derive.span, Mark::root()) .to_name_binding(self.arenas); result = Ok((binding, Flags::empty())); break; } - Err(Indeterminate) => result = Err(Determinacy::Undetermined), + Ok(_) | Err(Determinacy::Determined) => {} + Err(Determinacy::Undetermined) => + result = Err(Determinacy::Undetermined), } } result @@ -1004,7 +1002,8 @@ impl<'a> Resolver<'a> { } } - fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, descr: Symbol, span: Span) { + fn check_stability_and_deprecation(&self, ext: &SyntaxExtension, path: &ast::Path) { + let span = path.span; if let Some(stability) = &ext.stability { if let StabilityLevel::Unstable { reason, issue } = stability.level { let feature = stability.feature; @@ -1013,14 +1012,14 @@ impl<'a> Resolver<'a> { } } if let Some(depr) = &stability.rustc_depr { - let (message, lint) = stability::rustc_deprecation_message(depr, &descr.as_str()); + let (message, lint) = stability::rustc_deprecation_message(depr, &path.to_string()); stability::early_report_deprecation( self.session, &message, depr.suggestion, lint, span ); } } if let Some(depr) = &ext.deprecation { - let (message, lint) = stability::deprecation_message(depr, &descr.as_str()); + let (message, lint) = stability::deprecation_message(depr, &path.to_string()); stability::early_report_deprecation(self.session, &message, None, lint, span); } } @@ -1101,7 +1100,7 @@ impl<'a> Resolver<'a> { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. if ident.name == sym::cfg || ident.name == sym::cfg_attr || ident.name == sym::derive { - let macro_kind = self.opt_get_macro(res).map(|ext| ext.macro_kind()); + let macro_kind = self.get_macro(res).map(|ext| ext.macro_kind()); if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) { self.session.span_err( ident.span, &format!("name `{}` is reserved in attribute namespace", ident) diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index acf7a951856..c527ed02bc0 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 0d7f8d819ab..ab5cda43bfc 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 b60a34be434..7519cad9a96 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 4dc687451df..8639f622cd7 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 4eb038b4a55..4ae5e3e7308 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 e96cd4734d8..367638693d7 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 b836a508f7b..b211e2f8ed8 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 416078489f1..733b8d08f77 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 58f522cf823..fa57c20ecd5 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 3228b9c3013..0443b988b41 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 eb41ee45d22..cca08187527 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 e5f4df52237..4c2ad7d2fe9 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 6f84c450a2e..21c48bfe5e7 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 f85122922c8..c581a16dbb0 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 adf813c162a..7b954273071 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 -- cgit 1.4.1-3-g733a5 From 0ec6ea7333a8918a96f40110e014f2bbbd72281f Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Jul 2019 19:45:23 +0300 Subject: 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 + src/test/ui/hygiene/auxiliary/stdlib-prelude.rs | 3 +++ .../ui/hygiene/stdlib-prelude-from-opaque-early.rs | 21 +++++++++++++++++++++ .../ui/hygiene/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 795ff3faffa..1216a083700 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -2247,6 +2247,7 @@ impl<'a> Resolver<'a> { } if !module.no_implicit_prelude { + ident.span.adjust(Mark::root()); if ns == TypeNS { if let Some(binding) = self.extern_prelude_get(ident, !record_used) { return Some(LexicalScopeBinding::Item(binding)); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 077c126bdee..7ad54d572f4 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -856,6 +856,7 @@ impl<'a> Resolver<'a> { match self.hygienic_lexical_parent(module, &mut ident.span) { Some(parent_module) => WhereToResolve::Module(parent_module), None => { + ident.span.adjust(Mark::root()); use_prelude = !module.no_implicit_prelude; match ns { TypeNS => WhereToResolve::ExternPrelude, diff --git a/src/test/ui/hygiene/auxiliary/stdlib-prelude.rs b/src/test/ui/hygiene/auxiliary/stdlib-prelude.rs new file mode 100644 index 00000000000..81b0b7faa5b --- /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 00000000000..c8c5c72bf95 --- /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 00000000000..cf65de2bc23 --- /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() {} -- cgit 1.4.1-3-g733a5 From d1949b1ab01dbd482008f64af54161cc43bb0991 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Jul 2019 20:25:34 +0300 Subject: 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 68e7225c3cf..11c1fceb7e7 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -8,7 +8,7 @@ use crate::symbol::{Symbol, sym}; use crate::errors::Applicability; use syntax_pos::Span; - +use syntax_pos::hygiene::{Mark, SyntaxContext}; use rustc_data_structures::fx::FxHashSet; pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { @@ -55,12 +55,13 @@ pub fn add_derived_markers(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P names.insert(unwrap_or!(path.segments.get(0), continue).ident.name); } - cx.current_expansion.mark.set_expn_info(ExpnInfo::with_unstable( + let mark = Mark::fresh(cx.current_expansion.mark); + mark.set_expn_info(ExpnInfo::with_unstable( ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span, cx.parse_sess.edition, &[sym::rustc_attrs, sym::structural_match], )); - let span = span.with_ctxt(cx.backtrace()); + let span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); item.visit_attrs(|attrs| { if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) { let meta = cx.meta_word(span, sym::structural_match); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index 28d452233cc..ba2b2b7a2dd 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -117,7 +117,11 @@ impl Mark { #[inline] pub fn set_expn_info(self, info: ExpnInfo) { - HygieneData::with(|data| data.marks[self.0 as usize].expn_info = Some(info)) + HygieneData::with(|data| { + let old_info = &mut data.marks[self.0 as usize].expn_info; + assert!(old_info.is_none(), "expansion info is reset for a mark"); + *old_info = Some(info); + }) } pub fn is_descendant_of(self, ancestor: Mark) -> bool { -- cgit 1.4.1-3-g733a5 From 99c7432896bbfdab1f7f70f8d763cab5f3efe64a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 6 Jul 2019 21:02:45 +0300 Subject: 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 c44fd30be85..7e7bb5f61a3 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -60,7 +60,7 @@ use syntax::attr; use syntax::ast; use syntax::ast::*; use syntax::errors; -use syntax::ext::hygiene::{Mark, SyntaxContext}; +use syntax::ext::hygiene::Mark; use syntax::print::pprust; use syntax::source_map::{respan, ExpnInfo, ExpnKind, DesugaringKind, Spanned}; use syntax::std_inject; @@ -875,13 +875,11 @@ impl<'a> LoweringContext<'a> { span: Span, allow_internal_unstable: Option>, ) -> Span { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo { + span.fresh_expansion(Mark::root(), ExpnInfo { def_site: span, allow_internal_unstable, ..ExpnInfo::default(ExpnKind::Desugaring(reason), span, self.sess.edition()) - }); - span.with_ctxt(SyntaxContext::empty().apply_mark(mark)) + }) } fn with_anonymous_lifetime_mode( diff --git a/src/librustc/ty/query/on_disk_cache.rs b/src/librustc/ty/query/on_disk_cache.rs index 56c9474170c..d0be13a7111 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -588,41 +588,40 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { let expn_info_tag = u8::decode(self)?; - let ctxt = match expn_info_tag { + // FIXME(mw): This method does not restore `MarkData::parent` or + // `SyntaxContextData::prev_ctxt` or `SyntaxContextData::opaque`. These things + // don't seem to be used after HIR lowering, so everything should be fine + // as long as incremental compilation does not kick in before that. + let location = || Span::new(lo, hi, SyntaxContext::empty()); + let recover_from_expn_info = |this: &Self, expn_info, pos| { + let span = location().fresh_expansion(Mark::root(), expn_info); + this.synthetic_expansion_infos.borrow_mut().insert(pos, span.ctxt()); + span + }; + Ok(match expn_info_tag { TAG_NO_EXPANSION_INFO => { - SyntaxContext::empty() + location() } TAG_EXPANSION_INFO_INLINE => { - let pos = AbsoluteBytePos::new(self.opaque.position()); - let expn_info: ExpnInfo = Decodable::decode(self)?; - let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); - ctxt + let expn_info = Decodable::decode(self)?; + recover_from_expn_info( + self, expn_info, AbsoluteBytePos::new(self.opaque.position()) + ) } TAG_EXPANSION_INFO_SHORTHAND => { let pos = AbsoluteBytePos::decode(self)?; - let cached_ctxt = self.synthetic_expansion_infos - .borrow() - .get(&pos) - .cloned(); - - if let Some(ctxt) = cached_ctxt { - ctxt + if let Some(cached_ctxt) = self.synthetic_expansion_infos.borrow().get(&pos) { + Span::new(lo, hi, *cached_ctxt) } else { - let expn_info = self.with_position(pos.to_usize(), |this| { - ExpnInfo::decode(this) - })?; - let ctxt = SyntaxContext::allocate_directly(expn_info); - self.synthetic_expansion_infos.borrow_mut().insert(pos, ctxt); - ctxt + let expn_info = + self.with_position(pos.to_usize(), |this| ExpnInfo::decode(this))?; + recover_from_expn_info(self, expn_info, pos) } } _ => { unreachable!() } - }; - - Ok(Span::new(lo, hi, ctxt)) + }) } } diff --git a/src/librustc_allocator/expand.rs b/src/librustc_allocator/expand.rs index d0eefbb1179..9803ee99f1a 100644 --- a/src/librustc_allocator/expand.rs +++ b/src/librustc_allocator/expand.rs @@ -14,7 +14,7 @@ use syntax::{ base::{ExtCtxt, MacroKind, Resolver}, build::AstBuilder, expand::ExpansionConfig, - hygiene::{Mark, SyntaxContext}, + hygiene::Mark, }, mut_visit::{self, MutVisitor}, parse::ParseSess, @@ -84,16 +84,12 @@ impl MutVisitor for ExpandAllocatorDirectives<'_> { } self.found = true; - // Create a fresh Mark for the new macro expansion we are about to do - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo::with_unstable( + // Create a new expansion for the generated allocator code. + let span = item.span.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable( ExpnKind::Macro(MacroKind::Attr, sym::global_allocator), item.span, self.sess.edition, - &[sym::rustc_attrs], + [sym::rustc_attrs][..].into(), )); - // Tie the span to the macro expansion info we just created - let span = item.span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); - // Create an expansion config let ecfg = ExpansionConfig::default(self.crate_name.take().unwrap()); diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index 7ad54d572f4..6f276e04a5a 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -17,7 +17,7 @@ use syntax::errors::DiagnosticBuilder; use syntax::ext::base::{self, Indeterminate}; use syntax::ext::base::{MacroKind, SyntaxExtension}; use syntax::ext::expand::{AstFragment, Invocation, InvocationKind}; -use syntax::ext::hygiene::{self, Mark}; +use syntax::ext::hygiene::{self, Mark, ExpnInfo, ExpnKind}; use syntax::ext::tt::macro_rules; use syntax::feature_gate::{feature_err, emit_feature_err, is_builtin_attr_name}; use syntax::feature_gate::{AttributeGate, GateIssue, Stability, BUILTIN_ATTRIBUTES}; @@ -148,7 +148,10 @@ impl<'a> base::Resolver for Resolver<'a> { } fn get_module_scope(&mut self, id: ast::NodeId) -> Mark { - let mark = Mark::fresh(Mark::root()); + let span = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::default( + ExpnKind::Macro(MacroKind::Attr, sym::test_case), DUMMY_SP, self.session.edition() + )); + let mark = span.ctxt().outer(); let module = self.module_map[&self.definitions.local_def_id(id)]; self.definitions.set_invocation_parent(mark, module.def_id().unwrap().index); self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData { diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index cb4edee30cd..37d5885db60 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -721,6 +721,7 @@ pub struct ExtCtxt<'a> { pub resolver: &'a mut dyn Resolver, pub current_expansion: ExpansionData, pub expansions: FxHashMap>, + pub allow_derive_markers: Lrc<[Symbol]>, } impl<'a> ExtCtxt<'a> { @@ -740,6 +741,7 @@ impl<'a> ExtCtxt<'a> { directory_ownership: DirectoryOwnership::Owned { relative: None }, }, expansions: FxHashMap::default(), + allow_derive_markers: [sym::rustc_attrs, sym::structural_match][..].into(), } } diff --git a/src/libsyntax/ext/derive.rs b/src/libsyntax/ext/derive.rs index 11c1fceb7e7..1c15deab373 100644 --- a/src/libsyntax/ext/derive.rs +++ b/src/libsyntax/ext/derive.rs @@ -8,7 +8,6 @@ use crate::symbol::{Symbol, sym}; use crate::errors::Applicability; use syntax_pos::Span; -use syntax_pos::hygiene::{Mark, SyntaxContext}; use rustc_data_structures::fx::FxHashSet; pub fn collect_derives(cx: &mut ExtCtxt<'_>, attrs: &mut Vec) -> Vec { @@ -55,13 +54,11 @@ pub fn add_derived_markers(cx: &mut ExtCtxt<'_>, span: Span, traits: &[ast::P names.insert(unwrap_or!(path.segments.get(0), continue).ident.name); } - let mark = Mark::fresh(cx.current_expansion.mark); - mark.set_expn_info(ExpnInfo::with_unstable( + let span = span.fresh_expansion(cx.current_expansion.mark, ExpnInfo::allow_unstable( ExpnKind::Macro(MacroKind::Derive, Symbol::intern(&pretty_name)), span, - cx.parse_sess.edition, &[sym::rustc_attrs, sym::structural_match], + cx.parse_sess.edition, cx.allow_derive_markers.clone(), )); - let span = span.with_ctxt(SyntaxContext::empty().apply_mark(mark)); item.visit_attrs(|attrs| { if names.contains(&sym::Eq) && names.contains(&sym::PartialEq) { let meta = cx.meta_word(span, sym::structural_match); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 2349382eb5e..39a8a7af2a3 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -362,7 +362,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { derives.reserve(traits.len()); invocations.reserve(traits.len()); for path in traits { - let mark = Mark::fresh(self.cx.current_expansion.mark); + let mark = Mark::fresh(self.cx.current_expansion.mark, None); derives.push(mark); invocations.push(Invocation { kind: InvocationKind::Derive { @@ -847,7 +847,7 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { - let mark = Mark::fresh(self.cx.current_expansion.mark); + let mark = Mark::fresh(self.cx.current_expansion.mark, None); self.invocations.push(Invocation { kind, fragment_kind, diff --git a/src/libsyntax/std_inject.rs b/src/libsyntax/std_inject.rs index 81f9ff9b661..d86b76f71ec 100644 --- a/src/libsyntax/std_inject.rs +++ b/src/libsyntax/std_inject.rs @@ -1,7 +1,7 @@ use crate::ast; use crate::attr; use crate::edition::Edition; -use crate::ext::hygiene::{Mark, SyntaxContext, MacroKind}; +use crate::ext::hygiene::{Mark, MacroKind}; use crate::symbol::{Ident, Symbol, kw, sym}; use crate::source_map::{ExpnInfo, ExpnKind, dummy_spanned, respan}; use crate::ptr::P; @@ -9,19 +9,7 @@ use crate::tokenstream::TokenStream; use std::cell::Cell; use std::iter; -use syntax_pos::{DUMMY_SP, Span}; - -/// Craft a span that will be ignored by the stability lint's -/// call to source_map's `is_internal` check. -/// The expanded code uses the unstable `#[prelude_import]` attribute. -fn ignored_span(sp: Span, edition: Edition) -> Span { - let mark = Mark::fresh(Mark::root()); - mark.set_expn_info(ExpnInfo::with_unstable( - ExpnKind::Macro(MacroKind::Attr, Symbol::intern("std_inject")), sp, edition, - &[sym::prelude_import], - )); - sp.with_ctxt(SyntaxContext::empty().apply_mark(mark)) -} +use syntax_pos::DUMMY_SP; pub fn injected_crate_name() -> Option<&'static str> { INJECTED_CRATE_NAME.with(|name| name.get()) @@ -87,7 +75,11 @@ pub fn maybe_inject_crates_ref( INJECTED_CRATE_NAME.with(|opt_name| opt_name.set(Some(name))); - let span = ignored_span(DUMMY_SP, edition); + let span = DUMMY_SP.fresh_expansion(Mark::root(), ExpnInfo::allow_unstable( + ExpnKind::Macro(MacroKind::Attr, sym::std_inject), DUMMY_SP, edition, + [sym::prelude_import][..].into(), + )); + krate.module.items.insert(0, P(ast::Item { attrs: vec![ast::Attribute { style: ast::AttrStyle::Outer, diff --git a/src/libsyntax/test.rs b/src/libsyntax/test.rs index 7ec7bb6ff45..799d64a9962 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 0733a8ec95c..2f78644dff2 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 ba2b2b7a2dd..f060bf356f6 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -82,11 +82,8 @@ pub enum Transparency { } impl Mark { - pub fn fresh(parent: Mark) -> Self { - HygieneData::with(|data| { - data.marks.push(MarkData { parent, expn_info: None }); - Mark(data.marks.len() as u32 - 1) - }) + pub fn fresh(parent: Mark, expn_info: Option) -> Self { + HygieneData::with(|data| data.fresh_mark(parent, expn_info)) } /// The mark of the theoretical expansion that generates freshly parsed, unexpanded AST. @@ -180,6 +177,11 @@ impl HygieneData { GLOBALS.with(|globals| f(&mut *globals.hygiene_data.borrow_mut())) } + fn fresh_mark(&mut self, parent: Mark, expn_info: Option) -> Mark { + self.marks.push(MarkData { parent, expn_info }); + Mark(self.marks.len() as u32 - 1) + } + fn expn_info(&self, mark: Mark) -> Option<&ExpnInfo> { self.marks[mark.0 as usize].expn_info.as_ref() } @@ -396,33 +398,6 @@ impl SyntaxContext { SyntaxContext(raw) } - // Allocate a new SyntaxContext with the given ExpnInfo. This is used when - // deserializing Spans from the incr. comp. cache. - // FIXME(mw): This method does not restore MarkData::parent or - // SyntaxContextData::prev_ctxt or SyntaxContextData::opaque. These things - // don't seem to be used after HIR lowering, so everything should be fine - // as long as incremental compilation does not kick in before that. - pub fn allocate_directly(expansion_info: ExpnInfo) -> Self { - HygieneData::with(|data| { - data.marks.push(MarkData { - parent: Mark::root(), - expn_info: Some(expansion_info), - }); - - let mark = Mark(data.marks.len() as u32 - 1); - - data.syntax_contexts.push(SyntaxContextData { - outer_mark: mark, - transparency: Transparency::SemiTransparent, - prev_ctxt: SyntaxContext::empty(), - opaque: SyntaxContext::empty(), - opaque_and_semitransparent: SyntaxContext::empty(), - dollar_crate_name: kw::DollarCrate, - }); - SyntaxContext(data.syntax_contexts.len() as u32 - 1) - }) - } - /// Extend a syntax context with a given mark and default transparency for that mark. pub fn apply_mark(self, mark: Mark) -> SyntaxContext { HygieneData::with(|data| data.apply_mark(self, mark)) @@ -615,6 +590,20 @@ impl fmt::Debug for SyntaxContext { } } +impl Span { + /// Creates a fresh expansion with given properties. + /// Expansions are normally created by macros, but in some cases expansions are created for + /// other compiler-generated code to set per-span properties like allowed unstable features. + /// The returned span belongs to the created expansion and has the new properties, + /// but its location is inherited from the current span. + pub fn fresh_expansion(self, parent: Mark, expn_info: ExpnInfo) -> Span { + HygieneData::with(|data| { + let mark = data.fresh_mark(parent, Some(expn_info)); + self.with_ctxt(data.apply_mark(SyntaxContext::empty(), mark)) + }) + } +} + /// A subset of properties from both macro definition and macro call available through global data. /// Avoid using this if you have access to the original definition or call structures. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] @@ -669,10 +658,10 @@ impl ExpnInfo { } } - pub fn with_unstable(kind: ExpnKind, call_site: Span, edition: Edition, - allow_internal_unstable: &[Symbol]) -> ExpnInfo { + pub fn allow_unstable(kind: ExpnKind, call_site: Span, edition: Edition, + allow_internal_unstable: Lrc<[Symbol]>) -> ExpnInfo { ExpnInfo { - allow_internal_unstable: Some(allow_internal_unstable.into()), + allow_internal_unstable: Some(allow_internal_unstable), ..ExpnInfo::default(kind, call_site, edition) } } diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 89fcf3b1f8f..581fd47c4b3 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -508,6 +508,7 @@ symbols! { proc_macro_expr, proc_macro_gen, proc_macro_hygiene, + proc_macro_internals, proc_macro_mod, proc_macro_non_items, proc_macro_path_invoc, @@ -631,6 +632,7 @@ symbols! { static_nobundle, static_recursion, std, + std_inject, str, stringify, stmt, -- cgit 1.4.1-3-g733a5 From dcd30a4b175364ca1ee1efdcae701a23c5ff7d0b Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Jul 2019 13:02:05 +0300 Subject: 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 a770ab65c26..8db241e4b4e 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 9fa2c81954e..76fec1020f1 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 a7dfbd688c1..352d318ba79 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -372,7 +372,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { if let Some(k) = obligation.cause.span.desugaring_kind() { flags.push((sym::from_desugaring, None)); - flags.push((sym::from_desugaring, Some(k.descr().to_string()))); + flags.push((sym::from_desugaring, Some(format!("{:?}", k)))); } let generics = self.tcx.generics_of(def_id); let self_ty = trait_ref.self_ty(); diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index f060bf356f6..b72da042d04 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 4fd27ce4f96..9258b71518f 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -442,7 +442,7 @@ impl Span { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { let (pre, post) = match info.kind { - ExpnKind::Desugaring(..) => ("desugaring of `", "`"), + ExpnKind::Desugaring(..) => ("desugaring of ", ""), ExpnKind::Macro(macro_kind, _) => match macro_kind { MacroKind::Bang => ("", "!"), MacroKind::Attr => ("#[", "]"), -- cgit 1.4.1-3-g733a5 From eac900ac87828d6a4813f0c4a870bcdb439d1175 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Jul 2019 16:45:41 +0300 Subject: 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 69e8c355019..e0e7988a744 100644 --- a/src/librustc/ich/impls_syntax.rs +++ b/src/librustc/ich/impls_syntax.rs @@ -408,6 +408,7 @@ impl_stable_hash_for!(struct ::syntax_pos::hygiene::ExpnInfo { }); impl_stable_hash_for!(enum ::syntax_pos::hygiene::ExpnKind { + Root, Macro(kind, descr), Desugaring(kind) }); diff --git a/src/librustc/lint/mod.rs b/src/librustc/lint/mod.rs index 3c8b0041a98..e76c2493200 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 39a8a7af2a3..9a6252779e0 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -5,7 +5,7 @@ use crate::source_map::{dummy_spanned, respan}; use crate::config::StripUnconfigured; use crate::ext::base::*; use crate::ext::derive::{add_derived_markers, collect_derives}; -use crate::ext::hygiene::{Mark, SyntaxContext}; +use crate::ext::hygiene::{Mark, SyntaxContext, ExpnInfo, ExpnKind}; use crate::ext::placeholders::{placeholder, PlaceholderExpander}; use crate::feature_gate::{self, Features, GateIssue, is_builtin_attr, emit_feature_err}; use crate::mut_visit::*; @@ -847,7 +847,17 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { - let mark = Mark::fresh(self.cx.current_expansion.mark, None); + // Expansion info for all the collected invocations is set upon their resolution, + // with exception of the "derive container" case which is not resolved and can get + // its expansion info immediately. + let expn_info = match &kind { + InvocationKind::Attr { attr: None, item, .. } => Some(ExpnInfo::default( + ExpnKind::Macro(MacroKind::Attr, sym::derive), + item.span(), self.cx.parse_sess.edition, + )), + _ => None, + }; + let mark = Mark::fresh(self.cx.current_expansion.mark, expn_info); self.invocations.push(Invocation { kind, fragment_kind, diff --git a/src/libsyntax_pos/hygiene.rs b/src/libsyntax_pos/hygiene.rs index b72da042d04..5df14439230 100644 --- a/src/libsyntax_pos/hygiene.rs +++ b/src/libsyntax_pos/hygiene.rs @@ -59,6 +59,9 @@ pub struct Mark(u32); #[derive(Debug)] struct MarkData { parent: Mark, + /// Each mark should have an associated expansion info, but sometimes there's a delay between + /// creation of a mark and obtaining its info (e.g. macros are collected first and then + /// resolved later), so we use an `Option` here. expn_info: Option, } @@ -155,11 +158,11 @@ crate struct HygieneData { } impl HygieneData { - crate fn new() -> Self { + crate fn new(edition: Edition) -> Self { HygieneData { marks: vec![MarkData { parent: Mark::root(), - expn_info: None, + expn_info: Some(ExpnInfo::default(ExpnKind::Root, DUMMY_SP, edition)), }], syntax_contexts: vec![SyntaxContextData { outer_mark: Mark::root(), @@ -183,7 +186,15 @@ impl HygieneData { } fn expn_info(&self, mark: Mark) -> Option<&ExpnInfo> { - self.marks[mark.0 as usize].expn_info.as_ref() + if mark != Mark::root() { + Some(self.marks[mark.0 as usize].expn_info.as_ref() + .expect("no expansion info for a mark")) + } else { + // FIXME: Some code relies on `expn_info().is_none()` meaning "no expansion". + // Introduce a method for checking for "no expansion" instead and always return + // `ExpnInfo` from this function instead of the `Option`. + None + } } fn is_descendant_of(&self, mut mark: Mark, ancestor: Mark) -> bool { @@ -670,6 +681,8 @@ impl ExpnInfo { /// Expansion kind. #[derive(Clone, Debug, RustcEncodable, RustcDecodable)] pub enum ExpnKind { + /// No expansion, aka root expansion. Only `Mark::root()` has this kind. + Root, /// Expansion produced by a macro. /// FIXME: Some code injected by the compiler before HIR lowering also gets this kind. Macro(MacroKind, Symbol), @@ -680,6 +693,7 @@ pub enum ExpnKind { impl ExpnKind { pub fn descr(&self) -> Symbol { match *self { + ExpnKind::Root => kw::PathRoot, ExpnKind::Macro(_, descr) => descr, ExpnKind::Desugaring(kind) => Symbol::intern(kind.descr()), } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 9258b71518f..5ccfe5f0b8b 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -60,7 +60,7 @@ impl Globals { Globals { symbol_interner: Lock::new(symbol::Interner::fresh()), span_interner: Lock::new(span_encoding::SpanInterner::default()), - hygiene_data: Lock::new(hygiene::HygieneData::new()), + hygiene_data: Lock::new(hygiene::HygieneData::new(edition)), edition, } } @@ -442,6 +442,7 @@ impl Span { // Don't print recursive invocations. if !info.call_site.source_equal(&prev_span) { let (pre, post) = match info.kind { + ExpnKind::Root => break, ExpnKind::Desugaring(..) => ("desugaring of ", ""), ExpnKind::Macro(macro_kind, _) => match macro_kind { MacroKind::Bang => ("", "!"), -- cgit 1.4.1-3-g733a5 From 374a80a86de4dabae4975fae04fb67cc6e6dc0bb Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Jul 2019 18:29:22 +0300 Subject: 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 9a6252779e0..85a31b8b7e8 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -158,8 +158,8 @@ ast_fragments! { } impl AstFragmentKind { - fn dummy(self, span: Span) -> Option { - self.make_from(DummyResult::any(span)) + fn dummy(self, span: Span) -> AstFragment { + self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment") } fn expect_from_annotatables>(self, items: I) @@ -327,10 +327,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { - let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); - let fragment = self.expand_invoc(invoc, &ext).unwrap_or_else(|| { - invoc_fragment_kind.dummy(invoc_span).unwrap() - }); + let fragment = self.expand_invoc(invoc, &ext); self.collect_invocations(fragment, &[]) } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { if !item.derive_allowed() { @@ -477,7 +474,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> Option { + fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> AstFragment { if invoc.fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() { if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else { @@ -487,12 +484,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - let result = match invoc.kind { - InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext)?, - InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext)?, - InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext)?, - }; - if self.cx.current_expansion.depth > self.cx.ecfg.recursion_limit { let info = self.cx.current_expansion.mark.expn_info().unwrap(); let suggested_limit = self.cx.ecfg.recursion_limit * 2; @@ -507,15 +498,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { FatalError.raise(); } - Some(result) + match invoc.kind { + InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), + InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), + InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), + } } fn expand_attr_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option { + -> AstFragment { let (attr, mut item) = match invoc.kind { - InvocationKind::Attr { attr, item, .. } => (attr?, item), + InvocationKind::Attr { attr: Some(attr), item, .. } => (attr, item), _ => unreachable!(), }; @@ -526,13 +521,19 @@ impl<'a, 'b> MacroExpander<'a, 'b> { attr::mark_used(&attr); } item.visit_attrs(|attrs| attrs.push(attr)); - Some(invoc.fragment_kind.expect_from_annotatables(iter::once(item))) + invoc.fragment_kind.expect_from_annotatables(iter::once(item)) } SyntaxExtensionKind::LegacyAttr(expander) => { - let meta = attr.parse_meta(self.cx.parse_sess) - .map_err(|mut e| { e.emit(); }).ok()?; - let item = expander.expand(self.cx, attr.span, &meta, item); - Some(invoc.fragment_kind.expect_from_annotatables(item)) + match attr.parse_meta(self.cx.parse_sess) { + Ok(meta) => { + let item = expander.expand(self.cx, attr.span, &meta, item); + invoc.fragment_kind.expect_from_annotatables(item) + } + Err(mut err) => { + err.emit(); + invoc.fragment_kind.dummy(attr.span) + } + } } SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_attr_item(attr.span, &item); @@ -598,14 +599,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ); } - fn gate_proc_macro_expansion(&self, span: Span, fragment: &Option) { + fn gate_proc_macro_expansion(&self, span: Span, fragment: &AstFragment) { if self.cx.ecfg.proc_macro_hygiene() { return } - let fragment = match fragment { - Some(fragment) => fragment, - None => return, - }; fragment.visit_with(&mut DisallowMacros { span, @@ -641,7 +638,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_bang_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option { + -> AstFragment { let kind = invoc.fragment_kind; let (mac, span) = match invoc.kind { InvocationKind::Bang { mac, span } => (mac, span), @@ -649,7 +646,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; let path = &mac.node.path; - let opt_expanded = match &ext.kind { + match &ext.kind { SyntaxExtensionKind::Bang(expander) => { self.gate_proc_macro_expansion_kind(span, kind); let tok_result = expander.expand(self.cx, span, mac.node.stream()); @@ -659,19 +656,17 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } SyntaxExtensionKind::LegacyBang(expander) => { let tok_result = expander.expand(self.cx, span, mac.node.stream()); - kind.make_from(tok_result) + if let Some(result) = kind.make_from(tok_result) { + result + } else { + let msg = format!("non-{kind} macro in {kind} position: {name}", + name = path.segments[0].ident.name, kind = kind.name()); + self.cx.span_err(path.span, &msg); + self.cx.trace_macros_diag(); + kind.dummy(span) + } } _ => unreachable!() - }; - - if opt_expanded.is_some() { - opt_expanded - } else { - let msg = format!("non-{kind} macro in {kind} position: {name}", - name = path.segments[0].ident.name, kind = kind.name()); - self.cx.span_err(path.span, &msg); - self.cx.trace_macros_diag(); - kind.dummy(span) } } @@ -703,7 +698,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn expand_derive_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) - -> Option { + -> AstFragment { let (path, item) = match invoc.kind { InvocationKind::Derive { path, item, item_with_markers } => match ext.kind { SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers), @@ -712,7 +707,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { _ => unreachable!(), }; if !item.derive_allowed() { - return None; + return invoc.fragment_kind.dummy(path.span); } match &ext.kind { @@ -721,7 +716,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span: path.span, path }; let span = meta.span.with_ctxt(self.cx.backtrace()); let items = expander.expand(self.cx, span, &meta, item); - Some(invoc.fragment_kind.expect_from_annotatables(items)) + invoc.fragment_kind.expect_from_annotatables(items) } _ => unreachable!() } @@ -732,12 +727,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind: AstFragmentKind, path: &Path, span: Span) - -> Option { + -> AstFragment { let mut parser = self.cx.new_parser_from_tts(&toks.into_trees().collect::>()); match parser.parse_ast_fragment(kind, false) { Ok(fragment) => { parser.ensure_complete_parse(path, kind.name(), span); - Some(fragment) + fragment } Err(mut err) => { err.set_span(span); diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index 233d3dcfcb6..fc05012377b 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 -- cgit 1.4.1-3-g733a5 From b003dd6d9badf0e66b6e90af2052fefef94d4a43 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 7 Jul 2019 18:55:29 +0300 Subject: expand: Merge `expand_{bang,attr,derive}_invoc` into a single function It's more convenient to have all this highly related stuff together on one screen (for future refactorings). The `expand_invoc` function is compact enough now, after all the previous refactorings. --- src/libsyntax/ext/expand.rs | 194 ++++++++++++++-------------------- src/test/ui/macros/macro-error.stderr | 2 +- 2 files changed, 79 insertions(+), 117 deletions(-) diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 85a31b8b7e8..f1235e7174f 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -327,7 +327,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { - let fragment = self.expand_invoc(invoc, &ext); + let fragment = self.expand_invoc(invoc, &ext.kind); self.collect_invocations(fragment, &[]) } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { if !item.derive_allowed() { @@ -474,12 +474,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtension) -> AstFragment { - if invoc.fragment_kind == AstFragmentKind::ForeignItems && - !self.cx.ecfg.macros_in_extern() { - if let SyntaxExtensionKind::NonMacroAttr { .. } = ext.kind {} else { + fn expand_invoc(&mut self, invoc: Invocation, ext: &SyntaxExtensionKind) -> AstFragment { + let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); + if fragment_kind == AstFragmentKind::ForeignItems && !self.cx.ecfg.macros_in_extern() { + if let SyntaxExtensionKind::NonMacroAttr { .. } = ext {} else { emit_feature_err(&self.cx.parse_sess, sym::macros_in_extern, - invoc.span(), GateIssue::Language, + span, GateIssue::Language, "macro invocations in `extern {}` blocks are experimental"); } } @@ -499,58 +499,84 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } match invoc.kind { - InvocationKind::Bang { .. } => self.expand_bang_invoc(invoc, ext), - InvocationKind::Attr { .. } => self.expand_attr_invoc(invoc, ext), - InvocationKind::Derive { .. } => self.expand_derive_invoc(invoc, ext), - } - } - - fn expand_attr_invoc(&mut self, - invoc: Invocation, - ext: &SyntaxExtension) - -> AstFragment { - let (attr, mut item) = match invoc.kind { - InvocationKind::Attr { attr: Some(attr), item, .. } => (attr, item), - _ => unreachable!(), - }; - - match &ext.kind { - SyntaxExtensionKind::NonMacroAttr { mark_used } => { - attr::mark_known(&attr); - if *mark_used { - attr::mark_used(&attr); + InvocationKind::Bang { mac, .. } => match ext { + SyntaxExtensionKind::Bang(expander) => { + self.gate_proc_macro_expansion_kind(span, fragment_kind); + let tok_result = expander.expand(self.cx, span, mac.node.stream()); + let result = + self.parse_ast_fragment(tok_result, fragment_kind, &mac.node.path, span); + self.gate_proc_macro_expansion(span, &result); + result + } + SyntaxExtensionKind::LegacyBang(expander) => { + let tok_result = expander.expand(self.cx, span, mac.node.stream()); + if let Some(result) = fragment_kind.make_from(tok_result) { + result + } else { + let msg = format!("non-{kind} macro in {kind} position: {path}", + kind = fragment_kind.name(), path = mac.node.path); + self.cx.span_err(span, &msg); + self.cx.trace_macros_diag(); + fragment_kind.dummy(span) + } } - item.visit_attrs(|attrs| attrs.push(attr)); - invoc.fragment_kind.expect_from_annotatables(iter::once(item)) + _ => unreachable!() } - SyntaxExtensionKind::LegacyAttr(expander) => { - match attr.parse_meta(self.cx.parse_sess) { - Ok(meta) => { - let item = expander.expand(self.cx, attr.span, &meta, item); - invoc.fragment_kind.expect_from_annotatables(item) + InvocationKind::Attr { attr: Some(attr), mut item, .. } => match ext { + SyntaxExtensionKind::Attr(expander) => { + self.gate_proc_macro_attr_item(span, &item); + let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item { + Annotatable::Item(item) => token::NtItem(item), + Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()), + Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()), + Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()), + Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), + Annotatable::Expr(expr) => token::NtExpr(expr), + })), DUMMY_SP).into(); + let input = self.extract_proc_macro_attr_input(attr.tokens, span); + let tok_result = expander.expand(self.cx, span, input, item_tok); + let res = self.parse_ast_fragment(tok_result, fragment_kind, &attr.path, span); + self.gate_proc_macro_expansion(span, &res); + res + } + SyntaxExtensionKind::LegacyAttr(expander) => { + match attr.parse_meta(self.cx.parse_sess) { + Ok(meta) => { + let item = expander.expand(self.cx, span, &meta, item); + fragment_kind.expect_from_annotatables(item) + } + Err(mut err) => { + err.emit(); + fragment_kind.dummy(span) + } } - Err(mut err) => { - err.emit(); - invoc.fragment_kind.dummy(attr.span) + } + SyntaxExtensionKind::NonMacroAttr { mark_used } => { + attr::mark_known(&attr); + if *mark_used { + attr::mark_used(&attr); } + item.visit_attrs(|attrs| attrs.push(attr)); + fragment_kind.expect_from_annotatables(iter::once(item)) } + _ => unreachable!() } - SyntaxExtensionKind::Attr(expander) => { - self.gate_proc_macro_attr_item(attr.span, &item); - let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item { - Annotatable::Item(item) => token::NtItem(item), - Annotatable::TraitItem(item) => token::NtTraitItem(item.into_inner()), - Annotatable::ImplItem(item) => token::NtImplItem(item.into_inner()), - Annotatable::ForeignItem(item) => token::NtForeignItem(item.into_inner()), - Annotatable::Stmt(stmt) => token::NtStmt(stmt.into_inner()), - Annotatable::Expr(expr) => token::NtExpr(expr), - })), DUMMY_SP).into(); - let input = self.extract_proc_macro_attr_input(attr.tokens, attr.span); - let tok_result = expander.expand(self.cx, attr.span, input, item_tok); - let res = self.parse_ast_fragment(tok_result, invoc.fragment_kind, - &attr.path, attr.span); - self.gate_proc_macro_expansion(attr.span, &res); - res + InvocationKind::Derive { path, item, item_with_markers } => match ext { + SyntaxExtensionKind::Derive(expander) | + SyntaxExtensionKind::LegacyDerive(expander) => { + let (path, item) = match ext { + SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers), + _ => (path, item), + }; + if !item.derive_allowed() { + return fragment_kind.dummy(span); + } + let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span, path }; + let span = span.with_ctxt(self.cx.backtrace()); + let items = expander.expand(self.cx, span, &meta, item); + fragment_kind.expect_from_annotatables(items) + } + _ => unreachable!() } _ => unreachable!() } @@ -634,42 +660,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } } - /// Expand a macro invocation. Returns the resulting expanded AST fragment. - fn expand_bang_invoc(&mut self, - invoc: Invocation, - ext: &SyntaxExtension) - -> AstFragment { - let kind = invoc.fragment_kind; - let (mac, span) = match invoc.kind { - InvocationKind::Bang { mac, span } => (mac, span), - _ => unreachable!(), - }; - let path = &mac.node.path; - - match &ext.kind { - SyntaxExtensionKind::Bang(expander) => { - self.gate_proc_macro_expansion_kind(span, kind); - let tok_result = expander.expand(self.cx, span, mac.node.stream()); - let result = self.parse_ast_fragment(tok_result, kind, path, span); - self.gate_proc_macro_expansion(span, &result); - result - } - SyntaxExtensionKind::LegacyBang(expander) => { - let tok_result = expander.expand(self.cx, span, mac.node.stream()); - if let Some(result) = kind.make_from(tok_result) { - result - } else { - let msg = format!("non-{kind} macro in {kind} position: {name}", - name = path.segments[0].ident.name, kind = kind.name()); - self.cx.span_err(path.span, &msg); - self.cx.trace_macros_diag(); - kind.dummy(span) - } - } - _ => unreachable!() - } - } - fn gate_proc_macro_expansion_kind(&self, span: Span, kind: AstFragmentKind) { let kind = match kind { AstFragmentKind::Expr => "expressions", @@ -694,34 +684,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { ); } - /// Expand a derive invocation. Returns the resulting expanded AST fragment. - fn expand_derive_invoc(&mut self, - invoc: Invocation, - ext: &SyntaxExtension) - -> AstFragment { - let (path, item) = match invoc.kind { - InvocationKind::Derive { path, item, item_with_markers } => match ext.kind { - SyntaxExtensionKind::LegacyDerive(..) => (path, item_with_markers), - _ => (path, item), - } - _ => unreachable!(), - }; - if !item.derive_allowed() { - return invoc.fragment_kind.dummy(path.span); - } - - match &ext.kind { - SyntaxExtensionKind::Derive(expander) | - SyntaxExtensionKind::LegacyDerive(expander) => { - let meta = ast::MetaItem { node: ast::MetaItemKind::Word, span: path.span, path }; - let span = meta.span.with_ctxt(self.cx.backtrace()); - let items = expander.expand(self.cx, span, &meta, item); - invoc.fragment_kind.expect_from_annotatables(items) - } - _ => unreachable!() - } - } - fn parse_ast_fragment(&mut self, toks: TokenStream, kind: AstFragmentKind, diff --git a/src/test/ui/macros/macro-error.stderr b/src/test/ui/macros/macro-error.stderr index b3aed8c2cef..2539a6d5156 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 -- cgit 1.4.1-3-g733a5 From baddce5155f7358af319818b10c992790dc8c572 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 8 Jul 2019 01:00:43 +0300 Subject: 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 6f276e04a5a..fc1becfe309 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -221,14 +221,14 @@ impl<'a> base::Resolver for Resolver<'a> { fn resolve_macro_invocation(&mut self, invoc: &Invocation, invoc_id: Mark, force: bool) -> Result>, Indeterminate> { let (path, kind, derives_in_scope, after_derive) = match invoc.kind { - InvocationKind::Attr { attr: None, .. } => - return Ok(None), - InvocationKind::Attr { attr: Some(ref attr), ref traits, after_derive, .. } => - (&attr.path, MacroKind::Attr, traits.clone(), after_derive), + InvocationKind::Attr { ref attr, ref derives, after_derive, .. } => + (&attr.path, MacroKind::Attr, derives.clone(), after_derive), InvocationKind::Bang { ref mac, .. } => (&mac.node.path, MacroKind::Bang, Vec::new(), false), InvocationKind::Derive { ref path, .. } => (path, MacroKind::Derive, Vec::new(), false), + InvocationKind::DeriveContainer { .. } => + return Ok(None), }; let parent_scope = self.invoc_parent_scope(invoc_id, derives_in_scope); diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index f1235e7174f..7fc62e357c5 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -199,9 +199,10 @@ pub enum InvocationKind { span: Span, }, Attr { - attr: Option, - traits: Vec, + attr: ast::Attribute, item: Annotatable, + // Required for resolving derive helper attributes. + derives: Vec, // We temporarily report errors for attribute macros placed after derives after_derive: bool, }, @@ -210,15 +211,22 @@ pub enum InvocationKind { item: Annotatable, item_with_markers: Annotatable, }, + /// "Invocation" that contains all derives from an item, + /// broken into multiple `Derive` invocations when expanded. + /// FIXME: Find a way to remove it. + DeriveContainer { + derives: Vec, + item: Annotatable, + }, } impl Invocation { pub fn span(&self) -> Span { - match self.kind { - InvocationKind::Bang { span, .. } => span, - InvocationKind::Attr { attr: Some(ref attr), .. } => attr.span, - InvocationKind::Attr { attr: None, .. } => DUMMY_SP, - InvocationKind::Derive { ref path, .. } => path.span, + match &self.kind { + InvocationKind::Bang { span, .. } => *span, + InvocationKind::Attr { attr, .. } => attr.span, + InvocationKind::Derive { path, .. } => path.span, + InvocationKind::DeriveContainer { item, .. } => item.span(), } } } @@ -329,7 +337,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { let (expanded_fragment, new_invocations) = if let Some(ext) = ext { let fragment = self.expand_invoc(invoc, &ext.kind); self.collect_invocations(fragment, &[]) - } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { + } else if let InvocationKind::DeriveContainer { derives: traits, item } = invoc.kind { if !item.derive_allowed() { let attr = attr::find_by_name(item.attrs(), sym::derive) .expect("`derive` attribute should exist"); @@ -522,7 +530,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => unreachable!() } - InvocationKind::Attr { attr: Some(attr), mut item, .. } => match ext { + InvocationKind::Attr { attr, mut item, .. } => match ext { SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_attr_item(span, &item); let item_tok = TokenTree::token(token::Interpolated(Lrc::new(match item { @@ -578,7 +586,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { } _ => unreachable!() } - _ => unreachable!() + InvocationKind::DeriveContainer { .. } => unreachable!() } } @@ -805,10 +813,10 @@ struct InvocationCollector<'a, 'b> { impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> AstFragment { // Expansion info for all the collected invocations is set upon their resolution, - // with exception of the "derive container" case which is not resolved and can get + // with exception of the derive container case which is not resolved and can get // its expansion info immediately. let expn_info = match &kind { - InvocationKind::Attr { attr: None, item, .. } => Some(ExpnInfo::default( + InvocationKind::DeriveContainer { item, .. } => Some(ExpnInfo::default( ExpnKind::Macro(MacroKind::Attr, sym::derive), item.span(), self.cx.parse_sess.edition, )), @@ -833,12 +841,15 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { fn collect_attr(&mut self, attr: Option, - traits: Vec, + derives: Vec, item: Annotatable, kind: AstFragmentKind, after_derive: bool) -> AstFragment { - self.collect(kind, InvocationKind::Attr { attr, traits, item, after_derive }) + self.collect(kind, match attr { + Some(attr) => InvocationKind::Attr { attr, item, derives, after_derive }, + None => InvocationKind::DeriveContainer { derives, item }, + }) } fn find_attr_invoc(&self, attrs: &mut Vec, after_derive: &mut bool) -- cgit 1.4.1-3-g733a5 From 7b74d72d9a4414f088d7f638343d5d8a7c67084a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 8 Jul 2019 01:00:54 +0300 Subject: Fix failing tests --- src/librustc/ty/query/on_disk_cache.rs | 5 +++-- src/test/ui/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 d0be13a7111..a508d9846bc 100644 --- a/src/librustc/ty/query/on_disk_cache.rs +++ b/src/librustc/ty/query/on_disk_cache.rs @@ -610,8 +610,9 @@ impl<'a, 'tcx> SpecializedDecoder for CacheDecoder<'a, 'tcx> { } TAG_EXPANSION_INFO_SHORTHAND => { let pos = AbsoluteBytePos::decode(self)?; - if let Some(cached_ctxt) = self.synthetic_expansion_infos.borrow().get(&pos) { - Span::new(lo, hi, *cached_ctxt) + let cached_ctxt = self.synthetic_expansion_infos.borrow().get(&pos).cloned(); + if let Some(ctxt) = cached_ctxt { + Span::new(lo, hi, ctxt) } else { let expn_info = self.with_position(pos.to_usize(), |this| ExpnInfo::decode(this))?; diff --git a/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr b/src/test/ui/feature-gates/feature-gate-custom_test_frameworks.stderr index 1cc53db2c36..38304e7f3f9 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 -- cgit 1.4.1-3-g733a5 From e86e5cb38ffb9a55f6d9ab6ebda2d384fb154626 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 8 Jul 2019 21:58:42 +0300 Subject: 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 --- .../ui/derives/auxiliary/derive-marker-tricky.rs | 15 +++++++++ src/test/ui/derives/derive-marker-tricky.rs | 16 ++++++++++ .../ui/hygiene/extern-prelude-from-opaque-fail.rs | 28 ++++++++++++++++ .../hygiene/extern-prelude-from-opaque-fail.stderr | 37 ++++++++++++++++++++++ .../ui/macros/derive-in-eager-expansion-hang.rs | 14 ++++++++ .../macros/derive-in-eager-expansion-hang.stderr | 17 ++++++++++ .../proc-macro/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 00000000000..70345351bd0 --- /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 00000000000..730ea4714c7 --- /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 00000000000..06d62656e95 --- /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 00000000000..65133eb1e18 --- /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 00000000000..0729e14d5b2 --- /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 00000000000..1ef9427666b --- /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 a724d388f48..8a5e346c2b5 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 -- cgit 1.4.1-3-g733a5 From 29e7bfd0c74362e89197807655b17ede1ae321c0 Mon Sep 17 00:00:00 2001 From: John Kåre Alsaker Date: Fri, 19 Apr 2019 18:49:15 +0200 Subject: Refactor diagnostic emission for green nodes --- src/librustc/dep_graph/graph.rs | 86 ++++++++++++++++++++++++----------------- 1 file changed, 51 insertions(+), 35 deletions(-) diff --git a/src/librustc/dep_graph/graph.rs b/src/librustc/dep_graph/graph.rs index b8c6c1e3723..7eea336cbbf 100644 --- a/src/librustc/dep_graph/graph.rs +++ b/src/librustc/dep_graph/graph.rs @@ -7,6 +7,7 @@ use rustc_data_structures::sync::{Lrc, Lock, AtomicU32, Ordering}; use std::env; use std::hash::Hash; use std::collections::hash_map::Entry; +use std::mem; use crate::ty::{self, TyCtxt}; use crate::util::common::{ProfileQueriesMsg, profq_msg}; use parking_lot::{Mutex, Condvar}; @@ -61,11 +62,11 @@ struct DepGraphData { colors: DepNodeColorMap, - /// A set of loaded diagnostics that have been emitted. - emitted_diagnostics: Mutex>, + /// A set of loaded diagnostics that is in the progress of being emitted. + emitting_diagnostics: Mutex>, /// Used to wait for diagnostics to be emitted. - emitted_diagnostics_cond_var: Condvar, + emitting_diagnostics_cond_var: Condvar, /// When we load, there may be `.o` files, cached MIR, or other such /// things available to us. If we find that they are not dirty, we @@ -99,8 +100,8 @@ impl DepGraph { previous_work_products: prev_work_products, dep_node_debug: Default::default(), current: Lock::new(CurrentDepGraph::new(prev_graph_node_count)), - emitted_diagnostics: Default::default(), - emitted_diagnostics_cond_var: Condvar::new(), + emitting_diagnostics: Default::default(), + emitting_diagnostics_cond_var: Condvar::new(), previous: prev_graph, colors: DepNodeColorMap::new(prev_graph_node_count), loaded_from_cache: Default::default(), @@ -744,7 +745,7 @@ impl DepGraph { // There may be multiple threads trying to mark the same dep node green concurrently - let (dep_node_index, did_allocation) = { + let dep_node_index = { let mut current = data.current.borrow_mut(); // Copy the fingerprint from the previous graph, @@ -758,34 +759,36 @@ impl DepGraph { // ... emitting any stored diagnostic ... + // FIXME: Store the fact that a node has diagnostics in a bit in the dep graph somewhere + // Maybe store a list on disk and encode this fact in the DepNodeState let diagnostics = tcx.queries.on_disk_cache - .load_diagnostics(tcx, prev_dep_node_index); + .load_diagnostics(tcx, prev_dep_node_index); + + #[cfg(not(parallel_compiler))] + debug_assert!(data.colors.get(prev_dep_node_index).is_none(), + "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \ + insertion for {:?}", dep_node); if unlikely!(diagnostics.len() > 0) { self.emit_diagnostics( tcx, data, dep_node_index, - did_allocation, + prev_dep_node_index, diagnostics ); } // ... and finally storing a "Green" entry in the color map. // Multiple threads can all write the same color here - #[cfg(not(parallel_compiler))] - debug_assert!(data.colors.get(prev_dep_node_index).is_none(), - "DepGraph::try_mark_previous_green() - Duplicate DepNodeColor \ - insertion for {:?}", dep_node); - data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); debug!("try_mark_previous_green({:?}) - END - successfully marked as green", dep_node); Some(dep_node_index) } - /// Atomically emits some loaded diagnotics, assuming that this only gets called with - /// `did_allocation` set to `true` on a single thread. + /// Atomically emits some loaded diagnostics. + /// This may be called concurrently on multiple threads for the same dep node. #[cold] #[inline(never)] fn emit_diagnostics<'tcx>( @@ -793,36 +796,49 @@ impl DepGraph { tcx: TyCtxt<'tcx>, data: &DepGraphData, dep_node_index: DepNodeIndex, - did_allocation: bool, + prev_dep_node_index: SerializedDepNodeIndex, diagnostics: Vec, ) { - if did_allocation || !cfg!(parallel_compiler) { - // Only the thread which did the allocation emits the error messages - let handle = tcx.sess.diagnostic(); + let mut emitting = data.emitting_diagnostics.lock(); + + if data.colors.get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) { + // The node is already green so diagnostics must have been emitted already + return; + } + + if emitting.insert(dep_node_index) { + // We were the first to insert the node in the set so this thread + // must emit the diagnostics and signal other potentially waiting + // threads after. + mem::drop(emitting); // Promote the previous diagnostics to the current session. tcx.queries.on_disk_cache - .store_diagnostics(dep_node_index, diagnostics.clone().into()); + .store_diagnostics(dep_node_index, diagnostics.clone().into()); + + let handle = tcx.sess.diagnostic(); for diagnostic in diagnostics { DiagnosticBuilder::new_diagnostic(handle, diagnostic).emit(); } - #[cfg(parallel_compiler)] - { - // Mark the diagnostics and emitted and wake up waiters - data.emitted_diagnostics.lock().insert(dep_node_index); - data.emitted_diagnostics_cond_var.notify_all(); - } + // Mark the node as green now that diagnostics are emitted + data.colors.insert(prev_dep_node_index, DepNodeColor::Green(dep_node_index)); + + // Remove the node from the set + data.emitting_diagnostics.lock().remove(&dep_node_index); + + // Wake up waiters + data.emitting_diagnostics_cond_var.notify_all(); } else { - // The other threads will wait for the diagnostics to be emitted + // We must wait for the other thread to finish emitting the diagnostic - let mut emitted_diagnostics = data.emitted_diagnostics.lock(); loop { - if emitted_diagnostics.contains(&dep_node_index) { + data.emitting_diagnostics_cond_var.wait(&mut emitting); + if data.colors + .get(prev_dep_node_index) == Some(DepNodeColor::Green(dep_node_index)) { break; } - data.emitted_diagnostics_cond_var.wait(&mut emitted_diagnostics); } } } @@ -1027,7 +1043,7 @@ impl CurrentDepGraph { hash: self.anon_id_seed.combine(hasher.finish()), }; - self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO).0 + self.intern_node(target_dep_node, task_deps.reads, Fingerprint::ZERO) } fn alloc_node( @@ -1037,7 +1053,7 @@ impl CurrentDepGraph { fingerprint: Fingerprint ) -> DepNodeIndex { debug_assert!(!self.node_to_node_index.contains_key(&dep_node)); - self.intern_node(dep_node, edges, fingerprint).0 + self.intern_node(dep_node, edges, fingerprint) } fn intern_node( @@ -1045,11 +1061,11 @@ impl CurrentDepGraph { dep_node: DepNode, edges: SmallVec<[DepNodeIndex; 8]>, fingerprint: Fingerprint - ) -> (DepNodeIndex, bool) { + ) -> DepNodeIndex { debug_assert_eq!(self.node_to_node_index.len(), self.data.len()); match self.node_to_node_index.entry(dep_node) { - Entry::Occupied(entry) => (*entry.get(), false), + Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { let dep_node_index = DepNodeIndex::new(self.data.len()); self.data.push(DepNodeData { @@ -1058,7 +1074,7 @@ impl CurrentDepGraph { fingerprint }); entry.insert(dep_node_index); - (dep_node_index, true) + dep_node_index } } } -- cgit 1.4.1-3-g733a5