From 8db85a3c78bae764ea069aed9db7cf8012d13a48 Mon Sep 17 00:00:00 2001 From: Ibraheem Ahmed Date: Sat, 9 Oct 2021 11:28:20 -0400 Subject: [PATCH 1/5] add slice take methods --- library/core/src/ops/mod.rs | 3 + library/core/src/ops/range.rs | 18 +++ library/core/src/slice/mod.rs | 264 +++++++++++++++++++++++++++++++++- library/core/tests/lib.rs | 1 + library/core/tests/slice.rs | 109 ++++++++++++++ 5 files changed, 394 insertions(+), 1 deletion(-) diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index bd7feb8b183..6c866031370 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -181,6 +181,9 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[stable(feature = "inclusive_range", since = "1.26.0")] pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; +#[unstable(feature = "one_sided_range", issue = "69780")] +pub use self::range::OneSidedRange; + #[unstable(feature = "try_trait_v2", issue = "84277")] pub use self::try_trait::{FromResidual, Try}; diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index b74ba92c76e..11367220678 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -971,3 +971,21 @@ impl RangeBounds for RangeToInclusive<&T> { Included(self.end) } } + +/// `OneSidedRange` is implemented for built-in range types that are unbounded +/// on one side. For example, `a..`, `..b` and `..=c` implement `OneSidedRange`, +/// but `..`, `d..e`, and `f..=g` do not. +/// +/// Types that implement `OneSidedRange` must return `Bound::Unbounded` +/// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`. +#[unstable(feature = "one_sided_range", issue = "69780")] +pub trait OneSidedRange: RangeBounds {} + +#[unstable(feature = "one_sided_range", issue = "69780")] +impl OneSidedRange for RangeTo where Self: RangeBounds {} + +#[unstable(feature = "one_sided_range", issue = "69780")] +impl OneSidedRange for RangeFrom where Self: RangeBounds {} + +#[unstable(feature = "one_sided_range", issue = "69780")] +impl OneSidedRange for RangeToInclusive where Self: RangeBounds {} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index d876d944e7f..d5ce941b4ac 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -10,7 +10,7 @@ use crate::cmp::Ordering::{self, Greater, Less}; use crate::marker::Copy; use crate::mem; use crate::num::NonZeroUsize; -use crate::ops::{FnMut, Range, RangeBounds}; +use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; use crate::ptr; @@ -82,6 +82,29 @@ pub use index::range; #[unstable(feature = "inherent_ascii_escape", issue = "77174")] pub use ascii::EscapeAscii; +/// Calculates the direction and split point of a one-sided range. +/// +/// This is a helper function for `take` and `take_mut` that returns +/// the direction of the split (front or back) as well as the index at +/// which to split. Returns `None` if the split index would overflow. +#[inline] +fn split_point_of(range: impl OneSidedRange) -> Option<(Direction, usize)> { + use Bound::*; + + Some(match (range.start_bound(), range.end_bound()) { + (Unbounded, Excluded(i)) => (Direction::Front, *i), + (Unbounded, Included(i)) => (Direction::Front, i.checked_add(1)?), + (Excluded(i), Unbounded) => (Direction::Back, i.checked_add(1)?), + (Included(i), Unbounded) => (Direction::Back, *i), + _ => unreachable!(), + }) +} + +enum Direction { + Front, + Back, +} + #[lang = "slice"] #[cfg(not(test))] impl [T] { @@ -3576,6 +3599,245 @@ impl [T] { { self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i) } + + /// Removes the subslice corresponding to the given range + /// and returns a reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Taking the first three elements of a slice: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut first_three = slice.take(..3).unwrap(); + /// + /// assert_eq!(slice, &['d']); + /// assert_eq!(first_three, &['a', 'b', 'c']); + /// ``` + /// + /// Taking the last two elements of a slice: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// let mut tail = slice.take(2..).unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(tail, &['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.take(5..)); + /// assert_eq!(None, slice.take(..5)); + /// assert_eq!(None, slice.take(..=4)); + /// let expected: &[char] = &['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.take(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take<'a, R: OneSidedRange>(self: &mut &'a Self, range: R) -> Option<&'a Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = self.split_at(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the subslice corresponding to the given range + /// and returns a mutable reference to it. + /// + /// Returns `None` and does not modify the slice if the given + /// range is out of bounds. + /// + /// Note that this method only accepts one-sided ranges such as + /// `2..` or `..6`, but not `2..6`. + /// + /// # Examples + /// + /// Taking the first three elements of a slice: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut first_three = slice.take_mut(..3).unwrap(); + /// + /// assert_eq!(slice, &mut ['d']); + /// assert_eq!(first_three, &mut ['a', 'b', 'c']); + /// ``` + /// + /// Taking the last two elements of a slice: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// let mut tail = slice.take_mut(2..).unwrap(); + /// + /// assert_eq!(slice, &mut ['a', 'b']); + /// assert_eq!(tail, &mut ['c', 'd']); + /// ``` + /// + /// Getting `None` when `range` is out of bounds: + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// + /// assert_eq!(None, slice.take_mut(5..)); + /// assert_eq!(None, slice.take_mut(..5)); + /// assert_eq!(None, slice.take_mut(..=4)); + /// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd']; + /// assert_eq!(Some(expected), slice.take_mut(..4)); + /// ``` + #[inline] + #[must_use = "method does not modify the slice if the range is out of bounds"] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_mut<'a, R: OneSidedRange>( + self: &mut &'a mut Self, + range: R, + ) -> Option<&'a mut Self> { + let (direction, split_index) = split_point_of(range)?; + if split_index > self.len() { + return None; + } + let (front, back) = mem::take(self).split_at_mut(split_index); + match direction { + Direction::Front => { + *self = back; + Some(front) + } + Direction::Back => { + *self = front; + Some(back) + } + } + } + + /// Removes the first element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let first = slice.take_first().unwrap(); + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'a'); + /// ``` + #[inline] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> { + let (first, rem) = self.split_first()?; + *self = rem; + Some(first) + } + + /// Removes the first element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let first = slice.take_first_mut().unwrap(); + /// *first = 'd'; + /// + /// assert_eq!(slice, &['b', 'c']); + /// assert_eq!(first, &'d'); + /// ``` + #[inline] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + let (first, rem) = mem::take(self).split_first_mut()?; + *self = rem; + Some(first) + } + + /// Removes the last element of the slice and returns a reference + /// to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &[_] = &['a', 'b', 'c']; + /// let last = slice.take_last().unwrap(); + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'c'); + /// ``` + #[inline] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> { + let (last, rem) = self.split_last()?; + *self = rem; + Some(last) + } + + /// Removes the last element of the slice and returns a mutable + /// reference to it. + /// + /// Returns `None` if the slice is empty. + /// + /// # Examples + /// + /// ``` + /// #![feature(slice_take)] + /// + /// let mut slice: &mut [_] = &mut ['a', 'b', 'c']; + /// let last = slice.take_last_mut().unwrap(); + /// *last = 'd'; + /// + /// assert_eq!(slice, &['a', 'b']); + /// assert_eq!(last, &'d'); + /// ``` + #[inline] + #[unstable(feature = "slice_take", issue = "62280")] + pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> { + let (last, rem) = mem::take(self).split_last_mut()?; + *self = rem; + Some(last) + } } trait CloneFromSpec { diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index ce40bac3f31..adcd4e694ee 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -34,6 +34,7 @@ #![feature(pattern)] #![feature(sort_internals)] #![feature(slice_partition_at_index)] +#![feature(slice_take)] #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_array_assume_init)] #![feature(maybe_uninit_extra)] diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 8d05e47edf4..22ee8e5f72e 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -2232,3 +2232,112 @@ fn slice_split_array_mut_out_of_bounds() { v.split_array_mut::<7>(); } + +macro_rules! take_tests { + (slice: &[], $($tts:tt)*) => { + take_tests!(ty: &[()], slice: &[], $($tts)*); + }; + (slice: &mut [], $($tts:tt)*) => { + take_tests!(ty: &mut [()], slice: &mut [], $($tts)*); + }; + (slice: &$slice:expr, $($tts:tt)*) => { + take_tests!(ty: &[_], slice: &$slice, $($tts)*); + }; + (slice: &mut $slice:expr, $($tts:tt)*) => { + take_tests!(ty: &mut [_], slice: &mut $slice, $($tts)*); + }; + (ty: $ty:ty, slice: $slice:expr, method: $method:ident, $(($test_name:ident, ($($args:expr),*), $output:expr, $remaining:expr),)*) => { + $( + #[test] + fn $test_name() { + let mut slice: $ty = $slice; + assert_eq!($output, slice.$method($($args)*)); + let remaining: $ty = $remaining; + assert_eq!(remaining, slice); + } + )* + }; +} + +take_tests! { + slice: &[0, 1, 2, 3], method: take, + (take_in_bounds_range_to, (..1), Some(&[0] as _), &[1, 2, 3]), + (take_in_bounds_range_to_inclusive, (..=0), Some(&[0] as _), &[1, 2, 3]), + (take_in_bounds_range_from, (2..), Some(&[2, 3] as _), &[0, 1]), + (take_oob_range_to, (..5), None, &[0, 1, 2, 3]), + (take_oob_range_to_inclusive, (..=4), None, &[0, 1, 2, 3]), + (take_oob_range_from, (5..), None, &[0, 1, 2, 3]), +} + +take_tests! { + slice: &mut [0, 1, 2, 3], method: take_mut, + (take_mut_in_bounds_range_to, (..1), Some(&mut [0] as _), &mut [1, 2, 3]), + (take_mut_in_bounds_range_to_inclusive, (..=0), Some(&mut [0] as _), &mut [1, 2, 3]), + (take_mut_in_bounds_range_from, (2..), Some(&mut [2, 3] as _), &mut [0, 1]), + (take_mut_oob_range_to, (..5), None, &mut [0, 1, 2, 3]), + (take_mut_oob_range_to_inclusive, (..=4), None, &mut [0, 1, 2, 3]), + (take_mut_oob_range_from, (5..), None, &mut [0, 1, 2, 3]), +} + +take_tests! { + slice: &[1, 2], method: take_first, + (take_first_nonempty, (), Some(&1), &[2]), +} + +take_tests! { + slice: &mut [1, 2], method: take_first_mut, + (take_first_mut_nonempty, (), Some(&mut 1), &mut [2]), +} + +take_tests! { + slice: &[1, 2], method: take_last, + (take_last_nonempty, (), Some(&2), &[1]), +} + +take_tests! { + slice: &mut [1, 2], method: take_last_mut, + (take_last_mut_nonempty, (), Some(&mut 2), &mut [1]), +} + +take_tests! { + slice: &[], method: take_first, + (take_first_empty, (), None, &[]), +} + +take_tests! { + slice: &mut [], method: take_first_mut, + (take_first_mut_empty, (), None, &mut []), +} + +take_tests! { + slice: &[], method: take_last, + (take_last_empty, (), None, &[]), +} + +take_tests! { + slice: &mut [], method: take_last_mut, + (take_last_mut_empty, (), None, &mut []), +} + +const EMPTY_MAX: &'static [()] = &[(); usize::MAX]; + +// can't be a constant due to const mutability rules +macro_rules! empty_max_mut { + () => { + &mut [(); usize::MAX] as _ + }; +} + +take_tests! { + slice: &[(); usize::MAX], method: take, + (take_in_bounds_max_range_to, (..usize::MAX), Some(EMPTY_MAX), &[(); 0]), + (take_oob_max_range_to_inclusive, (..=usize::MAX), None, EMPTY_MAX), + (take_in_bounds_max_range_from, (usize::MAX..), Some(&[] as _), EMPTY_MAX), +} + +take_tests! { + slice: &mut [(); usize::MAX], method: take_mut, + (take_mut_in_bounds_max_range_to, (..usize::MAX), Some(empty_max_mut!()), &mut [(); 0]), + (take_mut_oob_max_range_to_inclusive, (..=usize::MAX), None, empty_max_mut!()), + (take_mut_in_bounds_max_range_from, (usize::MAX..), Some(&mut [] as _), empty_max_mut!()), +} From 141c6cc78ece04fb8330b2c28a42c025500d2d0e Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sun, 17 Oct 2021 19:32:34 +0300 Subject: [PATCH 2/5] expand: Turn `ast::Crate` into a first class expansion target And stop creating a fake `mod` item for the crate root when expanding a crate. --- compiler/rustc_ast/src/ast.rs | 2 + compiler/rustc_ast/src/ast_like.rs | 4 +- compiler/rustc_ast/src/mut_visit.rs | 37 +---- compiler/rustc_ast/src/visit.rs | 3 + compiler/rustc_ast_pretty/src/pprust/mod.rs | 9 ++ compiler/rustc_builtin_macros/src/cfg_eval.rs | 5 + .../rustc_builtin_macros/src/test_harness.rs | 58 ++++---- compiler/rustc_expand/src/base.rs | 19 ++- compiler/rustc_expand/src/expand.rs | 138 ++++++++---------- compiler/rustc_expand/src/placeholders.rs | 14 ++ compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_parse/src/lib.rs | 6 + compiler/rustc_parse/src/parser/item.rs | 2 +- .../rustc_resolve/src/build_reduced_graph.rs | 14 +- compiler/rustc_resolve/src/def_collector.rs | 14 +- .../ast-json/ast-json-noexpand-output.stdout | 2 +- src/test/ui/ast-json/ast-json-output.stdout | 2 +- .../ui/proc-macro/crate-attrs-multiple.rs | 14 ++ .../issue-59191-replace-root-with-fn.rs | 9 +- .../issue-59191-replace-root-with-fn.stderr | 8 +- 20 files changed, 203 insertions(+), 159 deletions(-) create mode 100644 src/test/ui/proc-macro/crate-attrs-multiple.rs diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 55b243a84a9..4d4c6217ad0 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -517,6 +517,8 @@ pub struct Crate { pub attrs: Vec, pub items: Vec>, pub span: Span, + // Placeholder ID if the crate node is a macro placeholder. + pub is_placeholder: Option, } /// Possible values inside of compile-time attribute lists. diff --git a/compiler/rustc_ast/src/ast_like.rs b/compiler/rustc_ast/src/ast_like.rs index d586426d70e..b9c397974a1 100644 --- a/compiler/rustc_ast/src/ast_like.rs +++ b/compiler/rustc_ast/src/ast_like.rs @@ -1,7 +1,7 @@ use super::ptr::P; use super::token::Nonterminal; use super::tokenstream::LazyTokenStream; -use super::{Arm, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; +use super::{Arm, Crate, ExprField, FieldDef, GenericParam, Param, PatField, Variant}; use super::{AssocItem, Expr, ForeignItem, Item, Local, MacCallStmt}; use super::{AttrItem, AttrKind, Block, Pat, Path, Ty, Visibility}; use super::{AttrVec, Attribute, Stmt, StmtKind}; @@ -276,7 +276,7 @@ derive_has_tokens_and_attrs! { // These ast nodes only support inert attributes, so they don't // store tokens (since nothing can observe them) derive_has_attrs_no_tokens! { - FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam + FieldDef, Arm, ExprField, PatField, Variant, Param, GenericParam, Crate } // These AST nodes don't support attributes, but can diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index fc5cc963992..205625573a6 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -284,6 +284,10 @@ pub trait MutVisitor: Sized { /// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful /// when using a `flat_map_*` or `filter_map_*` method within a `visit_` /// method. Abort the program if the closure panics. +/// +/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler. +/// Instead of aborting on catching a panic we need to reset the visited node to some valid but +/// possibly meaningless value and rethrow the panic. // // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`. pub fn visit_clobber(t: &mut T, f: F) @@ -1105,36 +1109,11 @@ pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { visit_unsafety(unsafety, vis); } -// FIXME: Avoid visiting the crate as a `Mod` item, flat map only the inner items if possible, -// or make crate visiting first class if necessary. pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { - visit_clobber(krate, |Crate { attrs, items, span }| { - let item_vis = - Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None }; - let item = P(Item { - ident: Ident::empty(), - attrs, - id: DUMMY_NODE_ID, - vis: item_vis, - span, - kind: ItemKind::Mod(Unsafe::No, ModKind::Loaded(items, Inline::Yes, span)), - tokens: None, - }); - let items = vis.flat_map_item(item); - - let len = items.len(); - if len == 0 { - Crate { attrs: vec![], items: vec![], span } - } else if len == 1 { - let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner(); - match kind { - ItemKind::Mod(_, ModKind::Loaded(items, ..)) => Crate { attrs, items, span }, - _ => panic!("visitor converted a module to not a module"), - } - } else { - panic!("a crate cannot expand to more than one item"); - } - }); + let Crate { attrs, items, span, is_placeholder: _ } = krate; + visit_attrs(attrs, vis); + items.flat_map_in_place(|item| vis.flat_map_item(item)); + vis.visit_span(span); } // Mutates one item into possibly many items. diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index be794ed221a..6840f092da6 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -211,6 +211,9 @@ pub trait Visitor<'ast>: Sized { fn visit_pat_field(&mut self, fp: &'ast PatField) { walk_pat_field(self, fp) } + fn visit_crate(&mut self, krate: &'ast Crate) { + walk_crate(self, krate) + } } #[macro_export] diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index e74f38dd89c..4b5703a429e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -75,3 +75,12 @@ pub fn attribute_to_string(attr: &ast::Attribute) -> String { pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { State::new().to_string(f) } + +pub fn crate_to_string_for_macros(krate: &ast::Crate) -> String { + State::new().to_string(|s| { + s.print_inner_attributes(&krate.attrs); + for item in &krate.items { + s.print_item(item); + } + }) +} diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 307730f7f5f..1dcab17f9ed 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -77,6 +77,10 @@ fn flat_map_annotatable( Annotatable::Param(param) => vis.flat_map_param(param).pop().map(Annotatable::Param), Annotatable::FieldDef(sf) => vis.flat_map_field_def(sf).pop().map(Annotatable::FieldDef), Annotatable::Variant(v) => vis.flat_map_variant(v).pop().map(Annotatable::Variant), + Annotatable::Crate(mut krate) => { + vis.visit_crate(&mut krate); + Some(Annotatable::Crate(krate)) + } } } @@ -101,6 +105,7 @@ impl CfgFinder { Annotatable::Param(param) => finder.visit_param(¶m), Annotatable::FieldDef(field) => finder.visit_field_def(&field), Annotatable::Variant(variant) => finder.visit_variant(&variant), + Annotatable::Crate(krate) => finder.visit_crate(krate), }; finder.has_cfg_or_cfg_attr } diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs index 64ccd4331e5..418729e7843 100644 --- a/compiler/rustc_builtin_macros/src/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -84,9 +84,35 @@ struct TestHarnessGenerator<'a> { tests: Vec, } +impl TestHarnessGenerator<'_> { + fn add_test_cases(&mut self, node_id: ast::NodeId, span: Span, prev_tests: Vec) { + let mut tests = mem::replace(&mut self.tests, prev_tests); + + if !tests.is_empty() { + // Create an identifier that will hygienically resolve the test + // case name, even in another module. + let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass( + span, + AstPass::TestHarness, + &[], + Some(node_id), + ); + for test in &mut tests { + // See the comment on `mk_main` for why we're using + // `apply_mark` directly. + test.ident.span = + test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque); + } + self.cx.test_cases.extend(tests); + } + } +} + impl<'a> MutVisitor for TestHarnessGenerator<'a> { fn visit_crate(&mut self, c: &mut ast::Crate) { + let prev_tests = mem::take(&mut self.tests); noop_visit_crate(c, self); + self.add_test_cases(ast::CRATE_NODE_ID, c.span, prev_tests); // Create a main function to run our tests c.items.push(mk_main(&mut self.cx)); @@ -103,34 +129,10 @@ impl<'a> MutVisitor for TestHarnessGenerator<'a> { // We don't want to recurse into anything other than mods, since // mods or tests inside of functions will break things - if let ast::ItemKind::Mod(..) = item.kind { - let tests = mem::take(&mut self.tests); + if let ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) = item.kind { + let prev_tests = mem::take(&mut self.tests); noop_visit_item_kind(&mut item.kind, self); - let mut tests = mem::replace(&mut self.tests, tests); - - if !tests.is_empty() { - let parent = - if item.id == ast::DUMMY_NODE_ID { ast::CRATE_NODE_ID } else { item.id }; - // Create an identifier that will hygienically resolve the test - // case name, even in another module. - let inner_span = match item.kind { - ast::ItemKind::Mod(_, ModKind::Loaded(.., span)) => span, - _ => unreachable!(), - }; - let expn_id = self.cx.ext_cx.resolver.expansion_for_ast_pass( - inner_span, - AstPass::TestHarness, - &[], - Some(parent), - ); - for test in &mut tests { - // See the comment on `mk_main` for why we're using - // `apply_mark` directly. - test.ident.span = - test.ident.span.apply_mark(expn_id.to_expn_id(), Transparency::Opaque); - } - self.cx.test_cases.extend(tests); - } + self.add_test_cases(item.id, span, prev_tests); } smallvec![P(item)] } @@ -146,7 +148,7 @@ fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPoin } else if sess.contains_name(&item.attrs, sym::rustc_main) { EntryPointType::MainAttr } else if item.ident.name == sym::main { - if depth == 1 { + if depth == 0 { // This is a top-level function so can be 'main' EntryPointType::MainNamed } else { diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index b630bc1f473..07b5e20b2dd 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -48,6 +48,7 @@ pub enum Annotatable { Param(ast::Param), FieldDef(ast::FieldDef), Variant(ast::Variant), + Crate(ast::Crate), } impl Annotatable { @@ -66,6 +67,7 @@ impl Annotatable { Annotatable::Param(ref p) => p.span, Annotatable::FieldDef(ref sf) => sf.span, Annotatable::Variant(ref v) => v.span, + Annotatable::Crate(ref c) => c.span, } } @@ -84,6 +86,7 @@ impl Annotatable { Annotatable::Param(p) => p.visit_attrs(f), Annotatable::FieldDef(sf) => sf.visit_attrs(f), Annotatable::Variant(v) => v.visit_attrs(f), + Annotatable::Crate(c) => c.visit_attrs(f), } } @@ -102,6 +105,7 @@ impl Annotatable { Annotatable::Param(p) => visitor.visit_param(p), Annotatable::FieldDef(sf) => visitor.visit_field_def(sf), Annotatable::Variant(v) => visitor.visit_variant(v), + Annotatable::Crate(c) => visitor.visit_crate(c), } } @@ -122,7 +126,8 @@ impl Annotatable { | Annotatable::GenericParam(..) | Annotatable::Param(..) | Annotatable::FieldDef(..) - | Annotatable::Variant(..) => panic!("unexpected annotatable"), + | Annotatable::Variant(..) + | Annotatable::Crate(..) => panic!("unexpected annotatable"), } } @@ -220,6 +225,13 @@ impl Annotatable { _ => panic!("expected variant"), } } + + pub fn expect_crate(self) -> ast::Crate { + match self { + Annotatable::Crate(krate) => krate, + _ => panic!("expected krate"), + } + } } /// Result of an expansion that may need to be retried. @@ -419,6 +431,11 @@ pub trait MacResult { fn make_variants(self: Box) -> Option> { None } + + fn make_crate(self: Box) -> Option { + // Fn-like macros cannot produce a crate. + unreachable!() + } } macro_rules! make_MacEager { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 89dbd64ed81..ba675daac41 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -14,13 +14,13 @@ use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{AstLike, Block, Inline, ItemKind, MacArgs, MacCall}; use rustc_ast::{MacCallStmt, MacStmtStyle, MetaItemKind, ModKind, NestedMetaItem}; -use rustc_ast::{NodeId, PatKind, Path, StmtKind, Unsafe}; +use rustc_ast::{NodeId, PatKind, Path, StmtKind}; use rustc_ast_pretty::pprust; use rustc_attr::is_builtin_attr; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, FatalError, PResult}; +use rustc_errors::{Applicability, PResult}; use rustc_feature::Features; use rustc_parse::parser::{ AttemptLocalParseRecovery, ForceCollect, Parser, RecoverColon, RecoverComma, @@ -33,7 +33,7 @@ use rustc_session::Limit; use rustc_span::symbol::{sym, Ident}; use rustc_span::{FileName, LocalExpnId, Span}; -use smallvec::{smallvec, SmallVec}; +use smallvec::SmallVec; use std::ops::DerefMut; use std::path::PathBuf; use std::rc::Rc; @@ -205,6 +205,7 @@ ast_fragments! { Variants(SmallVec<[ast::Variant; 1]>) { "variant"; many fn flat_map_variant; fn visit_variant(); fn make_variants; } + Crate(ast::Crate) { "crate"; one fn visit_crate; fn visit_crate; fn make_crate; } } pub enum SupportsMacroExpansion { @@ -227,9 +228,8 @@ impl AstFragmentKind { AstFragmentKind::Items | AstFragmentKind::TraitItems | AstFragmentKind::ImplItems - | AstFragmentKind::ForeignItems => { - SupportsMacroExpansion::Yes { supports_inner_attrs: true } - } + | AstFragmentKind::ForeignItems + | AstFragmentKind::Crate => SupportsMacroExpansion::Yes { supports_inner_attrs: true }, AstFragmentKind::Arms | AstFragmentKind::Fields | AstFragmentKind::FieldPats @@ -288,6 +288,9 @@ impl AstFragmentKind { AstFragmentKind::OptExpr => { AstFragment::OptExpr(items.next().map(Annotatable::expect_expr)) } + AstFragmentKind::Crate => { + AstFragment::Crate(items.next().expect("expected exactly one crate").expect_crate()) + } AstFragmentKind::Pat | AstFragmentKind::Ty => { panic!("patterns and types aren't annotatable") } @@ -359,9 +362,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { MacroExpander { cx, monotonic } } - // FIXME: Avoid visiting the crate as a `Mod` item, - // make crate a first class expansion target instead. - pub fn expand_crate(&mut self, mut krate: ast::Crate) -> ast::Crate { + pub fn expand_crate(&mut self, krate: ast::Crate) -> ast::Crate { let file_path = match self.cx.source_map().span_to_filename(krate.span) { FileName::Real(name) => name .into_local_path() @@ -375,52 +376,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { file_path_stack: vec![file_path], dir_path, }); - - let krate_item = AstFragment::Items(smallvec![P(ast::Item { - attrs: krate.attrs, - span: krate.span, - kind: ast::ItemKind::Mod( - Unsafe::No, - ModKind::Loaded(krate.items, Inline::Yes, krate.span) - ), - ident: Ident::empty(), - id: ast::DUMMY_NODE_ID, - vis: ast::Visibility { - span: krate.span.shrink_to_lo(), - kind: ast::VisibilityKind::Public, - tokens: None, - }, - tokens: None, - })]); - - match self.fully_expand_fragment(krate_item).make_items().pop().map(P::into_inner) { - Some(ast::Item { - attrs, - kind: ast::ItemKind::Mod(_, ModKind::Loaded(items, ..)), - .. - }) => { - krate.attrs = attrs; - krate.items = items; - } - None => { - // Resolution failed so we return an empty expansion - krate.attrs = vec![]; - krate.items = vec![]; - } - Some(ast::Item { span, kind, .. }) => { - krate.attrs = vec![]; - krate.items = vec![]; - self.cx.span_err( - span, - &format!( - "expected crate top-level item to be a module after macro expansion, found {} {}", - kind.article(), kind.descr() - ), - ); - // FIXME: this workaround issue #84569 - FatalError.raise(); - } - }; + let krate = self.fully_expand_fragment(AstFragment::Crate(krate)).make_crate(); self.cx.trace_macros_diag(); krate } @@ -708,26 +664,32 @@ impl<'a, 'b> MacroExpander<'a, 'b> { SyntaxExtensionKind::Attr(expander) => { self.gate_proc_macro_input(&item); self.gate_proc_macro_attr_item(span, &item); - let mut fake_tokens = false; - if let Annotatable::Item(item_inner) = &item { - if let ItemKind::Mod(_, mod_kind) = &item_inner.kind { - // FIXME: Collect tokens and use them instead of generating - // fake ones. These are unstable, so it needs to be - // fixed prior to stabilization - // Fake tokens when we are invoking an inner attribute, and: - fake_tokens = matches!(attr.style, ast::AttrStyle::Inner) && - // We are invoking an attribute on the crate root, or an outline - // module - (item_inner.ident.name.is_empty() || !matches!(mod_kind, ast::ModKind::Loaded(_, Inline::Yes, _))); - } - } - let tokens = if fake_tokens { - rustc_parse::fake_token_stream( + let tokens = match &item { + // FIXME: Collect tokens and use them instead of generating + // fake ones. These are unstable, so it needs to be + // fixed prior to stabilization + // Fake tokens when we are invoking an inner attribute, and + // we are invoking it on an out-of-line module or crate. + Annotatable::Crate(krate) => rustc_parse::fake_token_stream_for_crate( &self.cx.sess.parse_sess, - &item.into_nonterminal(), - ) - } else { - item.into_tokens(&self.cx.sess.parse_sess) + krate, + ), + Annotatable::Item(item_inner) + if matches!(attr.style, ast::AttrStyle::Inner) + && matches!( + item_inner.kind, + ItemKind::Mod( + _, + ModKind::Unloaded | ModKind::Loaded(_, Inline::No, _), + ) + ) => + { + rustc_parse::fake_token_stream( + &self.cx.sess.parse_sess, + &item.into_nonterminal(), + ) + } + _ => item.into_tokens(&self.cx.sess.parse_sess), }; let attr_item = attr.unwrap_normal_item(); if let MacArgs::Eq(..) = attr_item.args { @@ -804,7 +766,8 @@ impl<'a, 'b> MacroExpander<'a, 'b> { Annotatable::Item(_) | Annotatable::TraitItem(_) | Annotatable::ImplItem(_) - | Annotatable::ForeignItem(_) => return, + | Annotatable::ForeignItem(_) + | Annotatable::Crate(..) => return, Annotatable::Stmt(stmt) => { // Attributes are stable on item statements, // but unstable on all other kinds of statements @@ -949,6 +912,7 @@ pub fn parse_ast_fragment<'a>( RecoverComma::No, RecoverColon::Yes, )?), + AstFragmentKind::Crate => AstFragment::Crate(this.parse_crate_mod()?), AstFragmentKind::Arms | AstFragmentKind::Fields | AstFragmentKind::FieldPats @@ -1195,6 +1159,30 @@ macro_rules! assign_id { } impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { + fn visit_crate(&mut self, krate: &mut ast::Crate) { + let span = krate.span; + let empty_crate = + || ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None }; + let mut fold_crate = |krate: ast::Crate| { + let mut krate = match self.configure(krate) { + Some(krate) => krate, + None => return empty_crate(), + }; + + if let Some(attr) = self.take_first_attr(&mut krate) { + return self + .collect_attr(attr, Annotatable::Crate(krate), AstFragmentKind::Crate) + .make_crate(); + } + + noop_visit_crate(&mut krate, self); + krate + }; + + // Cannot use `visit_clobber` here, see the FIXME on it. + *krate = fold_crate(mem::replace(krate, empty_crate())); + } + fn visit_expr(&mut self, expr: &mut P) { self.cfg.configure_expr(expr); visit_clobber(expr.deref_mut(), |mut expr| { diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs index 12b6bc7bbe7..25b3a5820e6 100644 --- a/compiler/rustc_expand/src/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -46,6 +46,12 @@ pub fn placeholder( || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None }); match kind { + AstFragmentKind::Crate => AstFragment::Crate(ast::Crate { + attrs: Default::default(), + items: Default::default(), + span, + is_placeholder: Some(id), + }), AstFragmentKind::Expr => AstFragment::Expr(expr_placeholder()), AstFragmentKind::OptExpr => AstFragment::OptExpr(Some(expr_placeholder())), AstFragmentKind::Items => AstFragment::Items(smallvec![P(ast::Item { @@ -354,4 +360,12 @@ impl MutVisitor for PlaceholderExpander { _ => noop_visit_ty(ty, self), } } + + fn visit_crate(&mut self, krate: &mut ast::Crate) { + if let Some(id) = krate.is_placeholder { + *krate = self.remove(id).make_crate(); + } else { + noop_visit_crate(krate, self) + } + } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d3917dfb14a..dbee92cf598 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -323,7 +323,7 @@ pub fn configure_and_expand( let crate_attrs = krate.attrs.clone(); let extern_mod_loaded = |ident: Ident, attrs, items, span| { - let krate = ast::Crate { attrs, items, span }; + let krate = ast::Crate { attrs, items, span, is_placeholder: None }; pre_expansion_lint(sess, lint_store, &krate, &crate_attrs, &ident.name.as_str()); (krate.attrs, krate.items) }; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index a40f47f895b..2b1b2f3fce4 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -326,6 +326,12 @@ pub fn fake_token_stream(sess: &ParseSess, nt: &Nonterminal) -> TokenStream { parse_stream_from_source_str(filename, source, sess, Some(nt.span())) } +pub fn fake_token_stream_for_crate(sess: &ParseSess, krate: &ast::Crate) -> TokenStream { + let source = pprust::crate_to_string_for_macros(krate); + let filename = FileName::macro_expansion_source_code(&source); + parse_stream_from_source_str(filename, source, sess, Some(krate.span)) +} + pub fn parse_cfg_attr( attr: &Attribute, parse_sess: &ParseSess, diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 24a8df49ac7..cbeaf675be4 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -26,7 +26,7 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> { let (attrs, items, span) = self.parse_mod(&token::Eof)?; - Ok(ast::Crate { attrs, items, span }) + Ok(ast::Crate { attrs, items, span, is_placeholder: None }) } /// Parses a `mod { ... }` or `mod ;` item. diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 3cf9d324a38..26a5260b93f 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -651,11 +651,6 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { /// Constructs the reduced graph for one item. fn build_reduced_graph_for_item(&mut self, item: &'b Item) { - if matches!(item.kind, ItemKind::Mod(..)) && item.ident.name == kw::Empty { - // Fake crate root item from expand. - return; - } - let parent_scope = &self.parent_scope; let parent = parent_scope.module; let expansion = parent_scope.expansion; @@ -1499,4 +1494,13 @@ impl<'a, 'b> Visitor<'b> for BuildReducedGraphVisitor<'a, 'b> { visit::walk_variant(self, variant); } + + fn visit_crate(&mut self, krate: &'b ast::Crate) { + if let Some(id) = krate.is_placeholder { + self.visit_invoc_in_module(id); + } else { + visit::walk_crate(self, krate); + self.contains_macro_use(&krate.attrs); + } + } } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 5879cb1daa5..391baa85c61 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -7,7 +7,7 @@ use rustc_expand::expand::AstFragment; use rustc_hir::def_id::LocalDefId; use rustc_hir::definitions::*; use rustc_span::hygiene::LocalExpnId; -use rustc_span::symbol::{kw, sym}; +use rustc_span::symbol::sym; use rustc_span::Span; use tracing::debug; @@ -92,10 +92,6 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { // information we encapsulate into, the better let def_data = match &i.kind { ItemKind::Impl { .. } => DefPathData::Impl, - ItemKind::Mod(..) if i.ident.name == kw::Empty => { - // Fake crate root item from expand. - return visit::walk_item(self, i); - } ItemKind::Mod(..) | ItemKind::Trait(..) | ItemKind::TraitAlias(..) @@ -346,4 +342,12 @@ impl<'a, 'b> visit::Visitor<'a> for DefCollector<'a, 'b> { fn visit_field_def(&mut self, field: &'a FieldDef) { self.collect_field(field, None); } + + fn visit_crate(&mut self, krate: &'a Crate) { + if let Some(id) = krate.is_placeholder { + self.visit_macro_invoc(id) + } else { + visit::walk_crate(self, krate) + } + } } diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index 8961655ede3..22484ba6378 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}} +{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index 082f04134ce..ae56bef35ff 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0}} +{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"kind":{"variant":"Interpolated","fields":[{"variant":"NtExpr","fields":[{"id":0,"kind":{"variant":"Lit","fields":[{"token":{"kind":"Str","symbol":"lib","suffix":null},"kind":{"variant":"Str","fields":["lib","Cooked"]},"span":{"lo":0,"hi":0}}]},"span":{"lo":0,"hi":0},"attrs":{"0":null},"tokens":{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}}]}]},"span":{"lo":0,"hi":0}}]},"tokens":null},{"0":[[{"variant":"Token","fields":[{"kind":"Pound","span":{"lo":0,"hi":0}}]},"Joint"],[{"variant":"Token","fields":[{"kind":"Not","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Delimited","fields":[{"open":{"lo":0,"hi":0},"close":{"lo":0,"hi":0}},"Bracket",{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Ident","fields":["crate_type",false]},"span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":"Eq","span":{"lo":0,"hi":0}}]},"Alone"],[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"Alone"]]}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"rust_2015","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null},null]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"span":{"lo":0,"hi":0},"is_placeholder":null} diff --git a/src/test/ui/proc-macro/crate-attrs-multiple.rs b/src/test/ui/proc-macro/crate-attrs-multiple.rs new file mode 100644 index 00000000000..29a0eca4172 --- /dev/null +++ b/src/test/ui/proc-macro/crate-attrs-multiple.rs @@ -0,0 +1,14 @@ +// Multiple custom crate-level attributes, both inert and active. + +// check-pass +// aux-crate:test_macros=test-macros.rs + +#![feature(custom_inner_attributes)] +#![feature(prelude_import)] + +#![test_macros::identity_attr] +#![rustfmt::skip] +#![test_macros::identity_attr] +#![rustfmt::skip] + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs index 039878af56e..a4161d4fc3d 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.rs @@ -1,7 +1,10 @@ -// edition:2018 -// aux-crate:issue_59191=issue-59191.rs // Test that using a macro to replace the entire crate tree with a non-'mod' item errors out nicely. // `issue_59191::no_main` replaces whatever's passed in with `fn main() {}`. + +// edition:2018 +// aux-crate:issue_59191=issue-59191.rs +// error-pattern: requires `sized` lang_item + #![feature(custom_inner_attributes)] #![issue_59191::no_main] -//~^ ERROR expected crate top-level item to be a module after macro expansion, found a function +#![issue_59191::no_main] diff --git a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr index 126c52db548..f7516c7d377 100644 --- a/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr +++ b/src/test/ui/proc-macro/issue-59191-replace-root-with-fn.stderr @@ -1,10 +1,4 @@ -error: expected crate top-level item to be a module after macro expansion, found a function - --> $DIR/issue-59191-replace-root-with-fn.rs:6:1 - | -LL | #![issue_59191::no_main] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: this error originates in the attribute macro `issue_59191::no_main` (in Nightly builds, run with -Z macro-backtrace for more info) +error: requires `sized` lang_item error: aborting due to previous error From 0a273932902836710fcb8a8db1c91edc2a8fa0a9 Mon Sep 17 00:00:00 2001 From: Rich Kadel Date: Tue, 30 Nov 2021 15:40:55 -0800 Subject: [PATCH 3/5] Update LLVM with patches for better llvm-cov diagnostics Cherry-picks https://github.com/llvm/llvm-project/commit/ee88b8d63e475a75ae525563edfa95f6fcaac83a and https://github.com/llvm/llvm-project/commit/126e7611c70ca41782aa851c2bec132607eb8127 These patches to LLVM were added to help debug occasional errors that cause coverage reporting to fail. Prior to this patch, the only messaging was that the coverage data was malformed. Hopefully the improved messaging will help identify the root cause of these errors, when they arise, so we can make corrections to coverage output from Rust. --- src/llvm-project | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/llvm-project b/src/llvm-project index f9b03d0e2d7..01c8b654f9a 160000 --- a/src/llvm-project +++ b/src/llvm-project @@ -1 +1 @@ -Subproject commit f9b03d0e2d7378f8dd5697ceb72b310060f7598f +Subproject commit 01c8b654f9a01371414d1fd69cba38b289510a9e From 9de8a4a6faa320f2b972fbd4761cf2a85ef20277 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 1 Dec 2021 16:32:55 +0000 Subject: [PATCH 4/5] Include lint errors in error count for `-Ztreat-err-as-bug` This was a regression from https://github.com/rust-lang/rust/pull/87337; the `panic_if_treat_err_as_bug` function only checked the number of hard errors, not the number of lint errors. --- compiler/rustc_errors/src/lib.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index bb3d3a415e7..82a02c3e543 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -1013,7 +1013,9 @@ impl HandlerInner { } fn treat_err_as_bug(&self) -> bool { - self.flags.treat_err_as_bug.map_or(false, |c| self.err_count() >= c.get()) + self.flags + .treat_err_as_bug + .map_or(false, |c| self.err_count() + self.lint_err_count >= c.get()) } fn print_error_count(&mut self, registry: &Registry) { @@ -1205,7 +1207,10 @@ impl HandlerInner { fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { - match (self.err_count(), self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0)) { + match ( + self.err_count() + self.lint_err_count, + self.flags.treat_err_as_bug.map(|c| c.get()).unwrap_or(0), + ) { (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), (0, _) | (1, _) => {} (count, as_bug) => panic!( From 18ddf8d636289444a3bc0eaffde9e6c24eb621b4 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Wed, 1 Dec 2021 19:00:27 +0000 Subject: [PATCH 5/5] Use `try_normalize_erasing_regions` instead of a custom infer context This unfortunately is still giving an unsilenceable overflow error :( --- src/librustdoc/clean/mod.rs | 16 +++------------ src/test/rustdoc-ui/auxiliary/overflow.rs | 20 ++++++++++++++++++ src/test/rustdoc-ui/normalize-cycle.rs | 25 +++++++++++++++++++++++ src/test/rustdoc-ui/normalize-overflow.rs | 3 +++ 4 files changed, 51 insertions(+), 13 deletions(-) create mode 100644 src/test/rustdoc-ui/auxiliary/overflow.rs create mode 100644 src/test/rustdoc-ui/normalize-cycle.rs create mode 100644 src/test/rustdoc-ui/normalize-overflow.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 9b05716a67b..e131089f361 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1337,25 +1337,15 @@ fn normalize(cx: &mut DocContext<'tcx>, ty: Ty<'_>) -> Option> { return None; } - use crate::rustc_trait_selection::infer::TyCtxtInferExt; - use crate::rustc_trait_selection::traits::query::normalize::AtExt; - use rustc_middle::traits::ObligationCause; - // Try to normalize `::T` to a type let lifted = ty.lift_to_tcx(cx.tcx).unwrap(); - let normalized = cx.tcx.infer_ctxt().enter(|infcx| { - infcx - .at(&ObligationCause::dummy(), cx.param_env) - .normalize(lifted) - .map(|resolved| infcx.resolve_vars_if_possible(resolved.value)) - }); - match normalized { + match cx.tcx.try_normalize_erasing_regions(cx.param_env, lifted) { Ok(normalized_value) => { - debug!("normalized {:?} to {:?}", ty, normalized_value); + trace!("normalized {:?} to {:?}", ty, normalized_value); Some(normalized_value) } Err(err) => { - debug!("failed to normalize {:?}: {:?}", ty, err); + info!("failed to normalize {:?}: {:?}", ty, err); None } } diff --git a/src/test/rustdoc-ui/auxiliary/overflow.rs b/src/test/rustdoc-ui/auxiliary/overflow.rs new file mode 100644 index 00000000000..ff65936bec9 --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/overflow.rs @@ -0,0 +1,20 @@ +pub struct B0; +pub struct B1; +use std::ops::Shl; +use std::ops::Sub; +pub type Shleft = >::Output; +pub type Sub1 = >::Output; +pub struct UInt { + pub(crate) msb: U, + pub(crate) lsb: B, +} +impl Shl> for UInt +where + UInt: Sub, + UInt, B0>: Shl>>, +{ + type Output = Shleft, B0>, Sub1>>; + fn shl(self, rhs: UInt) -> Self::Output { + unimplemented!() + } +} diff --git a/src/test/rustdoc-ui/normalize-cycle.rs b/src/test/rustdoc-ui/normalize-cycle.rs new file mode 100644 index 00000000000..f48cad373cd --- /dev/null +++ b/src/test/rustdoc-ui/normalize-cycle.rs @@ -0,0 +1,25 @@ +// check-pass +// Regresion test for . +pub trait Query {} + +pub trait AsQuery { + type Query; +} + +impl AsQuery for T { + type Query = T; +} + +pub trait SelectDsl { + type Output; +} + +impl SelectDsl for T +where + T: AsQuery, + T::Query: SelectDsl, +{ + type Output = >::Output; +} + +pub type Select = >::Output; diff --git a/src/test/rustdoc-ui/normalize-overflow.rs b/src/test/rustdoc-ui/normalize-overflow.rs new file mode 100644 index 00000000000..0cdcc88e314 --- /dev/null +++ b/src/test/rustdoc-ui/normalize-overflow.rs @@ -0,0 +1,3 @@ +// aux-crate:overflow=overflow.rs +// check-pass +// Regression test for .