"winapi 0.3.8",
]
-[[package]]
-name = "autocfg"
-version = "0.1.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
-
[[package]]
name = "autocfg"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8"
dependencies = [
- "autocfg 1.0.0",
+ "autocfg",
"cfg-if",
"lazy_static",
]
[[package]]
name = "hashbrown"
-version = "0.6.2"
+version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cd9867f119b19fecb08cd5c326ad4488d7a1da4bf75b4d95d71db742525aaab"
+checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"
dependencies = [
- "autocfg 0.1.7",
+ "autocfg",
"compiler_builtins",
"rustc-std-workspace-alloc",
"rustc-std-workspace-core",
[[package]]
name = "indexmap"
-version = "1.0.2"
+version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
+checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"
+dependencies = [
+ "autocfg",
+ "hashbrown",
+]
[[package]]
name = "installer"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986"
dependencies = [
- "autocfg 1.0.0",
+ "autocfg",
"cc",
"libc",
"openssl-src",
"rustc_macros",
"rustc_serialize",
"rustc_span",
- "scoped-tls",
"smallvec 1.4.0",
"tracing",
]
"ansi_term 0.12.1",
"lazy_static",
"matchers",
- "parking_lot 0.9.0",
+ "parking_lot 0.10.2",
"regex",
"sharded-slab",
"smallvec 1.4.0",
+// ignore-tidy-filelength
+
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::Debug;
inner: IterMut<'a, K, V>,
}
+/// An owning iterator over the keys of a `BTreeMap`.
+///
+/// This `struct` is created by the [`into_keys`] method on [`BTreeMap`].
+/// See its documentation for more.
+///
+/// [`into_keys`]: BTreeMap::into_keys
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[derive(Debug)]
+pub struct IntoKeys<K, V> {
+ inner: IntoIter<K, V>,
+}
+
+/// An owning iterator over the values of a `BTreeMap`.
+///
+/// This `struct` is created by the [`into_values`] method on [`BTreeMap`].
+/// See its documentation for more.
+///
+/// [`into_values`]: BTreeMap::into_values
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+#[derive(Debug)]
+pub struct IntoValues<K, V> {
+ inner: IntoIter<K, V>,
+}
+
/// An iterator over a sub-range of entries in a `BTreeMap`.
///
/// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its
self.length = dfs(self.root.as_ref().unwrap().as_ref());
}
+
+ /// Creates a consuming iterator visiting all the keys, in sorted order.
+ /// The map cannot be used after calling this.
+ /// The iterator element type is `K`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_into_keys_values)]
+ /// use std::collections::BTreeMap;
+ ///
+ /// let mut a = BTreeMap::new();
+ /// a.insert(2, "b");
+ /// a.insert(1, "a");
+ ///
+ /// let keys: Vec<i32> = a.into_keys().collect();
+ /// assert_eq!(keys, [1, 2]);
+ /// ```
+ #[inline]
+ #[unstable(feature = "map_into_keys_values", issue = "75294")]
+ pub fn into_keys(self) -> IntoKeys<K, V> {
+ IntoKeys { inner: self.into_iter() }
+ }
+
+ /// Creates a consuming iterator visiting all the values, in order by key.
+ /// The map cannot be used after calling this.
+ /// The iterator element type is `V`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_into_keys_values)]
+ /// use std::collections::BTreeMap;
+ ///
+ /// let mut a = BTreeMap::new();
+ /// a.insert(1, "hello");
+ /// a.insert(2, "goodbye");
+ ///
+ /// let values: Vec<&str> = a.into_values().collect();
+ /// assert_eq!(values, ["hello", "goodbye"]);
+ /// ```
+ #[inline]
+ #[unstable(feature = "map_into_keys_values", issue = "75294")]
+ pub fn into_values(self) -> IntoValues<K, V> {
+ IntoValues { inner: self.into_iter() }
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap<K, V> {
+impl<'a, K, V> IntoIterator for &'a BTreeMap<K, V> {
type Item = (&'a K, &'a V);
type IntoIter = Iter<'a, K, V>;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap<K, V> {
+impl<'a, K, V> IntoIterator for &'a mut BTreeMap<K, V> {
type Item = (&'a K, &'a mut V);
type IntoIter = IterMut<'a, K, V>;
let (k, v) = kv.kv_mut();
if pred(k, v) {
*self.length -= 1;
- let RemoveResult { old_kv, pos, emptied_internal_root } = kv.remove_kv_tracking();
+ let (kv, pos) = kv.remove_kv_tracking(|_| self.emptied_internal_root = true);
self.cur_leaf_edge = Some(pos);
- self.emptied_internal_root |= emptied_internal_root;
- return Some(old_kv);
+ return Some(kv);
}
self.cur_leaf_edge = Some(kv.next_leaf_edge());
}
}
}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> Iterator for IntoKeys<K, V> {
+ type Item = K;
+
+ fn next(&mut self) -> Option<K> {
+ self.inner.next().map(|(k, _)| k)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+
+ fn last(mut self) -> Option<K> {
+ self.next_back()
+ }
+
+ fn min(mut self) -> Option<K> {
+ self.next()
+ }
+
+ fn max(mut self) -> Option<K> {
+ self.next_back()
+ }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> DoubleEndedIterator for IntoKeys<K, V> {
+ fn next_back(&mut self) -> Option<K> {
+ self.inner.next_back().map(|(k, _)| k)
+ }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> FusedIterator for IntoKeys<K, V> {}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> Iterator for IntoValues<K, V> {
+ type Item = V;
+
+ fn next(&mut self) -> Option<V> {
+ self.inner.next().map(|(_, v)| v)
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+
+ fn last(mut self) -> Option<V> {
+ self.next_back()
+ }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> DoubleEndedIterator for IntoValues<K, V> {
+ fn next_back(&mut self) -> Option<V> {
+ self.inner.next_back().map(|(_, v)| v)
+ }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> ExactSizeIterator for IntoValues<K, V> {
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> FusedIterator for IntoValues<K, V> {}
+
#[stable(feature = "btree_range", since = "1.17.0")]
impl<'a, K, V> DoubleEndedIterator for Range<'a, K, V> {
fn next_back(&mut self) -> Option<(&'a K, &'a V)> {
fn remove_kv(self) -> (K, V) {
*self.length -= 1;
- let RemoveResult { old_kv, pos, emptied_internal_root } = self.handle.remove_kv_tracking();
- let root = pos.into_node().into_root_mut();
- if emptied_internal_root {
- root.pop_internal_level();
- }
+ let (old_kv, _) =
+ self.handle.remove_kv_tracking(|root| root.into_root_mut().pop_internal_level());
old_kv
}
}
-struct RemoveResult<'a, K, V> {
- // Key and value removed.
- old_kv: (K, V),
- // Unique location at the leaf level that the removed KV lopgically collapsed into.
- pos: Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>,
- // Whether the remove left behind and empty internal root node, that should be removed
- // using `pop_internal_level`.
- emptied_internal_root: bool,
-}
-
impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInternal>, marker::KV> {
/// Removes a key/value-pair from the tree, and returns that pair, as well as
/// the leaf edge corresponding to that former pair. It's possible this leaves
/// an empty internal root node, which the caller should subsequently pop from
/// the map holding the tree. The caller should also decrement the map's length.
- fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> {
- let (mut pos, old_key, old_val, was_internal) = match self.force() {
+ fn remove_kv_tracking<F>(
+ self,
+ handle_emptied_internal_root: F,
+ ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>)
+ where
+ F: FnOnce(NodeRef<marker::Mut<'a>, K, V, marker::Internal>),
+ {
+ let (old_kv, mut pos, was_internal) = match self.force() {
Leaf(leaf) => {
- let (hole, old_key, old_val) = leaf.remove();
- (hole, old_key, old_val, false)
+ let (old_kv, pos) = leaf.remove();
+ (old_kv, pos, false)
}
Internal(mut internal) => {
// Replace the location freed in the internal node with the next KV,
let to_remove = internal.left_edge().descend().last_leaf_edge().left_kv().ok();
let to_remove = unsafe { unwrap_unchecked(to_remove) };
- let (hole, key, val) = to_remove.remove();
+ let (kv, pos) = to_remove.remove();
- let old_key = unsafe { mem::replace(&mut *key_loc, key) };
- let old_val = unsafe { mem::replace(&mut *val_loc, val) };
+ let old_key = unsafe { mem::replace(&mut *key_loc, kv.0) };
+ let old_val = unsafe { mem::replace(&mut *val_loc, kv.1) };
- (hole, old_key, old_val, true)
+ ((old_key, old_val), pos, true)
}
};
// Handle underflow
- let mut emptied_internal_root = false;
let mut cur_node = unsafe { ptr::read(&pos).into_node().forget_type() };
let mut at_leaf = true;
while cur_node.len() < node::MIN_LEN {
let parent = edge.into_node();
if parent.len() == 0 {
- // This empty parent must be the root, and should be popped off the tree.
- emptied_internal_root = true;
+ // The parent that was just emptied must be the root,
+ // because nodes on a lower level would not have been
+ // left underfull. It has to be popped off the tree soon.
+ handle_emptied_internal_root(parent);
break;
} else {
cur_node = parent.forget_type();
pos = unsafe { unwrap_unchecked(pos.next_kv().ok()).next_leaf_edge() };
}
- RemoveResult { old_kv: (old_key, old_val), pos, emptied_internal_root }
+ (old_kv, pos)
}
}
+use core::intrinsics;
+use core::mem;
use core::ptr;
use super::node::{marker, ForceResult::*, Handle, NodeRef};
def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv}
/// This replaces the value behind the `v` unique reference by calling the
-/// relevant function.
+/// relevant function, and returns a result obtained along the way.
///
-/// Safety: The change closure must not panic.
+/// If a panic occurs in the `change` closure, the entire process will be aborted.
#[inline]
-unsafe fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
+fn replace<T, R>(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R {
+ struct PanicGuard;
+ impl Drop for PanicGuard {
+ fn drop(&mut self) {
+ intrinsics::abort()
+ }
+ }
+ let guard = PanicGuard;
let value = unsafe { ptr::read(v) };
let (new_value, ret) = change(value);
unsafe {
ptr::write(v, new_value);
}
+ mem::forget(guard);
ret
}
/// key and value in between.
/// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree.
pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) {
- unsafe {
- replace(self, |leaf_edge| {
- let kv = leaf_edge.next_kv();
- let kv = unwrap_unchecked(kv.ok());
- (kv.next_leaf_edge(), kv.into_kv())
- })
- }
+ replace(self, |leaf_edge| {
+ let kv = leaf_edge.next_kv();
+ let kv = unsafe { unwrap_unchecked(kv.ok()) };
+ (kv.next_leaf_edge(), kv.into_kv())
+ })
}
/// Moves the leaf edge handle to the previous leaf edge and returns references to the
/// key and value in between.
/// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree.
pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) {
- unsafe {
- replace(self, |leaf_edge| {
- let kv = leaf_edge.next_back_kv();
- let kv = unwrap_unchecked(kv.ok());
- (kv.next_back_leaf_edge(), kv.into_kv())
- })
- }
+ replace(self, |leaf_edge| {
+ let kv = leaf_edge.next_back_kv();
+ let kv = unsafe { unwrap_unchecked(kv.ok()) };
+ (kv.next_back_leaf_edge(), kv.into_kv())
+ })
}
}
/// - The caller must ensure that the leaf edge is not the last one in the tree.
/// - Using the updated handle may well invalidate the returned references.
pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
- unsafe {
- let kv = replace(self, |leaf_edge| {
- let kv = leaf_edge.next_kv();
- let kv = unwrap_unchecked(kv.ok());
- (ptr::read(&kv).next_leaf_edge(), kv)
- });
- // Doing the descend (and perhaps another move) invalidates the references
- // returned by `into_kv_mut`, so we have to do this last.
- kv.into_kv_mut()
- }
+ let kv = replace(self, |leaf_edge| {
+ let kv = leaf_edge.next_kv();
+ let kv = unsafe { unwrap_unchecked(kv.ok()) };
+ (unsafe { ptr::read(&kv) }.next_leaf_edge(), kv)
+ });
+ // Doing the descend (and perhaps another move) invalidates the references
+ // returned by `into_kv_mut`, so we have to do this last.
+ kv.into_kv_mut()
}
/// Moves the leaf edge handle to the previous leaf and returns references to the
/// - The caller must ensure that the leaf edge is not the first one in the tree.
/// - Using the updated handle may well invalidate the returned references.
pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) {
- unsafe {
- let kv = replace(self, |leaf_edge| {
- let kv = leaf_edge.next_back_kv();
- let kv = unwrap_unchecked(kv.ok());
- (ptr::read(&kv).next_back_leaf_edge(), kv)
- });
- // Doing the descend (and perhaps another move) invalidates the references
- // returned by `into_kv_mut`, so we have to do this last.
- kv.into_kv_mut()
- }
+ let kv = replace(self, |leaf_edge| {
+ let kv = leaf_edge.next_back_kv();
+ let kv = unsafe { unwrap_unchecked(kv.ok()) };
+ (unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv)
+ });
+ // Doing the descend (and perhaps another move) invalidates the references
+ // returned by `into_kv_mut`, so we have to do this last.
+ kv.into_kv_mut()
}
}
/// call this method again subject to both preconditions listed in the first point,
/// or call counterpart `next_back_unchecked` subject to its preconditions.
pub unsafe fn next_unchecked(&mut self) -> (K, V) {
- unsafe {
- replace(self, |leaf_edge| {
- let kv = next_kv_unchecked_dealloc(leaf_edge);
- let k = ptr::read(kv.reborrow().into_kv().0);
- let v = ptr::read(kv.reborrow().into_kv().1);
- (kv.next_leaf_edge(), (k, v))
- })
- }
+ replace(self, |leaf_edge| {
+ let kv = unsafe { next_kv_unchecked_dealloc(leaf_edge) };
+ let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
+ let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
+ (kv.next_leaf_edge(), (k, v))
+ })
}
/// Moves the leaf edge handle to the previous leaf edge and returns the key
/// call this method again subject to both preconditions listed in the first point,
/// or call counterpart `next_unchecked` subject to its preconditions.
pub unsafe fn next_back_unchecked(&mut self) -> (K, V) {
- unsafe {
- replace(self, |leaf_edge| {
- let kv = next_back_kv_unchecked_dealloc(leaf_edge);
- let k = ptr::read(kv.reborrow().into_kv().0);
- let v = ptr::read(kv.reborrow().into_kv().1);
- (kv.next_back_leaf_edge(), (k, v))
- })
- }
+ replace(self, |leaf_edge| {
+ let kv = unsafe { next_back_kv_unchecked_dealloc(leaf_edge) };
+ let k = unsafe { ptr::read(kv.reborrow().into_kv().0) };
+ let v = unsafe { ptr::read(kv.reborrow().into_kv().1) };
+ (kv.next_back_leaf_edge(), (k, v))
+ })
}
}
/// between the now adjacent key/value pairs (if any) to the left and right of this handle.
pub fn remove(
mut self,
- ) -> (Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>, K, V) {
+ ) -> ((K, V), Handle<NodeRef<marker::Mut<'a>, K, V, marker::Leaf>, marker::Edge>) {
unsafe {
let k = slice_remove(self.node.keys_mut(), self.idx);
let v = slice_remove(self.node.vals_mut(), self.idx);
(*self.node.as_leaf_mut()).len -= 1;
- (self.left_edge(), k, v)
+ ((k, v), self.left_edge())
}
}
}
///
/// # Safety
///
- /// The `ptr` must be allocated (via the given allocator `a`), and with the given `capacity`.
+ /// The `ptr` must be allocated (via the given allocator `alloc`), and with the given
+ /// `capacity`.
/// The `capacity` cannot exceed `isize::MAX` for sized types. (only a concern on 32-bit
/// systems). ZST vectors may have a capacity up to `usize::MAX`.
- /// If the `ptr` and `capacity` come from a `RawVec` created via `a`, then this is guaranteed.
+ /// If the `ptr` and `capacity` come from a `RawVec` created via `alloc`, then this is
+ /// guaranteed.
#[inline]
- pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, a: A) -> Self {
- Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc: a }
+ pub unsafe fn from_raw_parts_in(ptr: *mut T, capacity: usize, alloc: A) -> Self {
+ Self { ptr: unsafe { Unique::new_unchecked(ptr) }, cap: capacity, alloc }
}
/// Gets a raw pointer to the start of the allocation. Note that this is
assert_eq!(DROPS.load(Ordering::SeqCst), size);
}
}
+
+#[test]
+fn test_into_keys() {
+ let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: BTreeMap<_, _> = vec.into_iter().collect();
+ let keys: Vec<_> = map.into_keys().collect();
+
+ assert_eq!(keys.len(), 3);
+ assert!(keys.contains(&1));
+ assert!(keys.contains(&2));
+ assert!(keys.contains(&3));
+}
+
+#[test]
+fn test_into_values() {
+ let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: BTreeMap<_, _> = vec.into_iter().collect();
+ let values: Vec<_> = map.into_values().collect();
+
+ assert_eq!(values.len(), 3);
+ assert!(values.contains(&'a'));
+ assert!(values.contains(&'b'));
+ assert!(values.contains(&'c'));
+}
#![feature(drain_filter)]
#![feature(exact_size_is_empty)]
#![feature(map_first_last)]
+#![feature(map_into_keys_values)]
#![feature(new_uninit)]
#![feature(pattern)]
#![feature(str_split_once)]
// FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it
// works with const generics:
- // `mem::transmute::<[T; {N}], [MaybeUninit<T>; {N}]>(array)`
+ // `mem::transmute::<[T; N], [MaybeUninit<T>; N]>(array)`
//
- // Until then, we do it manually here. We first create a bitwise copy
- // but cast the pointer so that it is treated as a different type. Then
- // we forget `array` so that it is not dropped.
- let data = unsafe {
- let data = ptr::read(&array as *const [T; N] as *const [MaybeUninit<T>; N]);
+ // Until then, we can use `mem::transmute_copy` to create a bitwise copy
+ // as a different type, then forget `array` so that it is not dropped.
+ unsafe {
+ let iter = Self { data: mem::transmute_copy(&array), alive: 0..N };
mem::forget(array);
- data
- };
-
- Self { data, alive: 0..N }
+ iter
+ }
}
/// Returns an immutable slice of all elements that have not been yielded
/// yet.
fn as_slice(&self) -> &[T] {
- let slice = &self.data[self.alive.clone()];
- // SAFETY: This transmute is safe. As mentioned in `new`, `MaybeUninit` retains
- // the size and alignment of `T`. Furthermore, we know that all
- // elements within `alive` are properly initialized.
- unsafe { mem::transmute::<&[MaybeUninit<T>], &[T]>(slice) }
+ // SAFETY: We know that all elements within `alive` are properly initialized.
+ unsafe {
+ let slice = self.data.get_unchecked(self.alive.clone());
+ MaybeUninit::slice_get_ref(slice)
+ }
}
/// Returns a mutable slice of all elements that have not been yielded yet.
fn as_mut_slice(&mut self) -> &mut [T] {
- // This transmute is safe, same as in `as_slice` above.
- let slice = &mut self.data[self.alive.clone()];
- // SAFETY: This transmute is safe. As mentioned in `new`, `MaybeUninit` retains
- // the size and alignment of `T`. Furthermore, we know that all
- // elements within `alive` are properly initialized.
- unsafe { mem::transmute::<&mut [MaybeUninit<T>], &mut [T]>(slice) }
+ // SAFETY: We know that all elements within `alive` are properly initialized.
+ unsafe {
+ let slice = self.data.get_unchecked_mut(self.alive.clone());
+ MaybeUninit::slice_get_mut(slice)
+ }
}
}
impl<T, const N: usize> Iterator for IntoIter<T, N> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
- if self.alive.start == self.alive.end {
- return None;
- }
-
- // Bump start index.
+ // Get the next index from the front.
//
- // From the check above we know that `alive.start != alive.end`.
- // Combine this with the invariant `alive.start <= alive.end`, we know
- // that `alive.start < alive.end`. Increasing `alive.start` by 1
- // maintains the invariant regarding `alive`. However, due to this
- // change, for a short time, the alive zone is not `data[alive]`
- // anymore, but `data[idx..alive.end]`.
- let idx = self.alive.start;
- self.alive.start += 1;
-
- // Read the element from the array.
- // SAFETY: This is safe: `idx` is an index
- // into the "alive" region of the array. Reading this element means
- // that `data[idx]` is regarded as dead now (i.e. do not touch). As
- // `idx` was the start of the alive-zone, the alive zone is now
- // `data[alive]` again, restoring all invariants.
- let out = unsafe { self.data.get_unchecked(idx).read() };
-
- Some(out)
+ // Increasing `alive.start` by 1 maintains the invariant regarding
+ // `alive`. However, due to this change, for a short time, the alive
+ // zone is not `data[alive]` anymore, but `data[idx..alive.end]`.
+ self.alive.next().map(|idx| {
+ // Read the element from the array.
+ // SAFETY: `idx` is an index into the former "alive" region of the
+ // array. Reading this element means that `data[idx]` is regarded as
+ // dead now (i.e. do not touch). As `idx` was the start of the
+ // alive-zone, the alive zone is now `data[alive]` again, restoring
+ // all invariants.
+ unsafe { self.data.get_unchecked(idx).read() }
+ })
}
fn size_hint(&self) -> (usize, Option<usize>) {
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T, const N: usize> DoubleEndedIterator for IntoIter<T, N> {
fn next_back(&mut self) -> Option<Self::Item> {
- if self.alive.start == self.alive.end {
- return None;
- }
-
- // Decrease end index.
+ // Get the next index from the back.
//
- // From the check above we know that `alive.start != alive.end`.
- // Combine this with the invariant `alive.start <= alive.end`, we know
- // that `alive.start < alive.end`. As `alive.start` cannot be negative,
- // `alive.end` is at least 1, meaning that we can safely decrement it
- // by one. This also maintains the invariant `alive.start <=
- // alive.end`. However, due to this change, for a short time, the alive
- // zone is not `data[alive]` anymore, but `data[alive.start..alive.end
- // + 1]`.
- self.alive.end -= 1;
-
- // Read the element from the array.
- // SAFETY: This is safe: `alive.end` is an
- // index into the "alive" region of the array. Compare the previous
- // comment that states that the alive region is
- // `data[alive.start..alive.end + 1]`. Reading this element means that
- // `data[alive.end]` is regarded as dead now (i.e. do not touch). As
- // `alive.end` was the end of the alive-zone, the alive zone is now
- // `data[alive]` again, restoring all invariants.
- let out = unsafe { self.data.get_unchecked(self.alive.end).read() };
-
- Some(out)
+ // Decreasing `alive.end` by 1 maintains the invariant regarding
+ // `alive`. However, due to this change, for a short time, the alive
+ // zone is not `data[alive]` anymore, but `data[alive.start..=idx]`.
+ self.alive.next_back().map(|idx| {
+ // Read the element from the array.
+ // SAFETY: `idx` is an index into the former "alive" region of the
+ // array. Reading this element means that `data[idx]` is regarded as
+ // dead now (i.e. do not touch). As `idx` was the end of the
+ // alive-zone, the alive zone is now `data[alive]` again, restoring
+ // all invariants.
+ unsafe { self.data.get_unchecked(idx).read() }
+ })
}
}
#[stable(feature = "array_value_iter_impls", since = "1.40.0")]
impl<T: Clone, const N: usize> Clone for IntoIter<T, N> {
fn clone(&self) -> Self {
- // SAFETY: each point of unsafety is documented inside the unsafe block
- unsafe {
- // This creates a new uninitialized array. Note that the `assume_init`
- // refers to the array, not the individual elements. And it is Ok if
- // the array is in an uninitialized state as all elements may be
- // uninitialized (all bit patterns are valid). Compare the
- // `MaybeUninit` docs for more information.
- let mut new_data: [MaybeUninit<T>; N] = MaybeUninit::uninit().assume_init();
-
- // Clone all alive elements.
- for idx in self.alive.clone() {
- // The element at `idx` in the old array is alive, so we can
- // safely call `get_ref()`. We then clone it, and write the
- // clone into the new array.
- let clone = self.data.get_unchecked(idx).get_ref().clone();
- new_data.get_unchecked_mut(idx).write(clone);
- }
-
- Self { data: new_data, alive: self.alive.clone() }
+ // Note, we don't really need to match the exact same alive range, so
+ // we can just clone into offset 0 regardless of where `self` is.
+ let mut new = Self { data: MaybeUninit::uninit_array(), alive: 0..0 };
+
+ // Clone all alive elements.
+ for (src, dst) in self.as_slice().iter().zip(&mut new.data) {
+ // Write a clone into the new array, then update its alive range.
+ // If cloning panics, we'll correctly drop the previous items.
+ dst.write(src.clone());
+ new.alive.end += 1;
}
+
+ new
}
}
// box. This isn't the greatest implementation since it probably deoptimizes
// more than we want, but it's so far good enough.
+ #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri.
// SAFETY: the inline assembly is a no-op.
unsafe {
llvm_asm!("" : : "r"(&dummy));
- dummy
}
+
+ dummy
}
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
/// until they are, it is advisable to avoid them.)
#[stable(feature = "maybe_uninit", since = "1.36.0")]
+ #[rustc_const_unstable(feature = "const_maybe_uninit_as_ptr", issue = "75251")]
#[inline(always)]
- pub fn as_ptr(&self) -> *const T {
- unsafe { &*self.value as *const T }
+ pub const fn as_ptr(&self) -> *const T {
+ // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
+ self as *const _ as *const T
}
/// Gets a mutable pointer to the contained value. Reading from this pointer or turning it
/// (Notice that the rules around references to uninitialized data are not finalized yet, but
/// until they are, it is advisable to avoid them.)
#[stable(feature = "maybe_uninit", since = "1.36.0")]
+ #[rustc_const_unstable(feature = "const_maybe_uninit_as_ptr", issue = "75251")]
#[inline(always)]
- pub fn as_mut_ptr(&mut self) -> *mut T {
- unsafe { &mut *self.value as *mut T }
+ pub const fn as_mut_ptr(&mut self) -> *mut T {
+ // `MaybeUninit` and `ManuallyDrop` are both `repr(transparent)` so we can cast the pointer.
+ self as *mut _ as *mut T
}
/// Extracts the value from the `MaybeUninit<T>` container. This is a great way
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute them to arrays of bytes
- #[allow_internal_unstable(const_fn_union)]
+ #[allow_internal_unstable(const_fn_transmute)]
#[inline]
pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
- #[repr(C)]
- union Bytes {
- val: $SelfT,
- bytes: [u8; mem::size_of::<$SelfT>()],
- }
// SAFETY: integers are plain old datatypes so we can always transmute them to
// arrays of bytes
- unsafe { Bytes { val: self }.bytes }
+ unsafe { mem::transmute(self) }
}
}
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute to them
- #[allow_internal_unstable(const_fn_union)]
+ #[allow_internal_unstable(const_fn_transmute)]
#[inline]
pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- #[repr(C)]
- union Bytes {
- val: $SelfT,
- bytes: [u8; mem::size_of::<$SelfT>()],
- }
// SAFETY: integers are plain old datatypes so we can always transmute to them
- unsafe { Bytes { bytes }.val }
+ unsafe { mem::transmute(bytes) }
}
}
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute them to arrays of bytes
- #[allow_internal_unstable(const_fn_union)]
+ #[allow_internal_unstable(const_fn_transmute)]
#[inline]
pub const fn to_ne_bytes(self) -> [u8; mem::size_of::<Self>()] {
- #[repr(C)]
- union Bytes {
- val: $SelfT,
- bytes: [u8; mem::size_of::<$SelfT>()],
- }
// SAFETY: integers are plain old datatypes so we can always transmute them to
// arrays of bytes
- unsafe { Bytes { val: self }.bytes }
+ unsafe { mem::transmute(self) }
}
}
doc_comment! {
- concat!("Create an integer value from its representation as a byte array in
-big endian.
+ concat!("Create a native endian integer value from its representation
+as a byte array in big endian.
",
$from_xe_bytes_doc,
"
doc_comment! {
concat!("
-Create an integer value from its representation as a byte array in
-little endian.
+Create a native endian integer value from its representation
+as a byte array in little endian.
",
$from_xe_bytes_doc,
"
}
doc_comment! {
- concat!("Create an integer value from its memory representation as a byte
-array in native endianness.
+ concat!("Create a native endian integer value from its memory representation
+as a byte array in native endianness.
As the target platform's native endianness is used, portable code
likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as
#[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")]
// SAFETY: const sound because integers are plain old datatypes so we can always
// transmute to them
- #[allow_internal_unstable(const_fn_union)]
+ #[allow_internal_unstable(const_fn_transmute)]
#[inline]
pub const fn from_ne_bytes(bytes: [u8; mem::size_of::<Self>()]) -> Self {
- #[repr(C)]
- union Bytes {
- val: $SelfT,
- bytes: [u8; mem::size_of::<$SelfT>()],
- }
// SAFETY: integers are plain old datatypes so we can always transmute to them
- unsafe { Bytes { bytes }.val }
+ unsafe { mem::transmute(bytes) }
}
}
self.wrapping_offset((count as isize).wrapping_neg())
}
+ /// Sets the pointer value to `ptr`.
+ ///
+ /// In case `self` is a (fat) pointer to an unsized type, this operation
+ /// will only affect the pointer part, whereas for (thin) pointers to
+ /// sized types, this has the same effect as a simple assignment.
+ ///
+ /// # Examples
+ ///
+ /// This function is primarily useful for allowing byte-wise pointer
+ /// arithmetic on potentially fat pointers:
+ ///
+ /// ```
+ /// #![feature(set_ptr_value)]
+ /// # use core::fmt::Debug;
+ /// let arr: [i32; 3] = [1, 2, 3];
+ /// let mut ptr = &arr[0] as *const dyn Debug;
+ /// let thin = ptr as *const u8;
+ /// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() });
+ /// assert_eq!(unsafe { *(ptr as *const i32) }, 3);
+ /// ```
+ #[unstable(feature = "set_ptr_value", issue = "75091")]
+ #[inline]
+ pub fn set_ptr_value(mut self, val: *const ()) -> Self {
+ let thin = &mut self as *mut *const T as *mut *const ();
+ // SAFETY: In case of a thin pointer, this operations is identical
+ // to a simple assignment. In case of a fat pointer, with the current
+ // fat pointer layout implementation, the first field of such a
+ // pointer is always the data pointer, which is likewise assigned.
+ unsafe { *thin = val };
+ self
+ }
+
/// Reads the value from `self` without moving it. This leaves the
/// memory in `self` unchanged.
///
self.wrapping_offset((count as isize).wrapping_neg())
}
+ /// Sets the pointer value to `ptr`.
+ ///
+ /// In case `self` is a (fat) pointer to an unsized type, this operation
+ /// will only affect the pointer part, whereas for (thin) pointers to
+ /// sized types, this has the same effect as a simple assignment.
+ ///
+ /// # Examples
+ ///
+ /// This function is primarily useful for allowing byte-wise pointer
+ /// arithmetic on potentially fat pointers:
+ ///
+ /// ```
+ /// #![feature(set_ptr_value)]
+ /// # use core::fmt::Debug;
+ /// let mut arr: [i32; 3] = [1, 2, 3];
+ /// let mut ptr = &mut arr[0] as *mut dyn Debug;
+ /// let thin = ptr as *mut u8;
+ /// ptr = ptr.set_ptr_value(unsafe { thin.add(8).cast() });
+ /// assert_eq!(unsafe { *(ptr as *mut i32) }, 3);
+ /// ```
+ #[unstable(feature = "set_ptr_value", issue = "75091")]
+ #[inline]
+ pub fn set_ptr_value(mut self, val: *mut ()) -> Self {
+ let thin = &mut self as *mut *mut T as *mut *mut ();
+ // SAFETY: In case of a thin pointer, this operations is identical
+ // to a simple assignment. In case of a fat pointer, with the current
+ // fat pointer layout implementation, the first field of such a
+ // pointer is always the data pointer, which is likewise assigned.
+ unsafe { *thin = val };
+ self
+ }
+
/// Reads the value from `self` without moving it. This leaves the
/// memory in `self` unchanged.
///
/// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer
/// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`.
+ ///
+ /// # Safety
+ ///
+ /// When calling this method, you have to ensure that all of the following is true:
+ /// - `self` is properly aligned
+ /// - `self` must point to an initialized instance of T; in particular, the pointer must be
+ /// "dereferencable" in the sense defined [here].
+ ///
+ /// This applies even if the result of this method is unused!
+ /// (The part about being initialized is not yet fully decided, but until
+ /// it is, the only safe approach is to ensure that they are indeed initialized.)
+ ///
+ /// Additionally, the lifetime of `self` does not necessarily reflect the actual
+ /// lifetime of the data. *You* must enforce Rust's aliasing rules. In particular,
+ /// for the duration of this lifetime, the memory the pointer points to must not
+ /// get mutated (except inside `UnsafeCell`).
+ ///
+ /// [here]: crate::ptr#safety
#[stable(feature = "nonnull", since = "1.25.0")]
#[inline]
pub unsafe fn as_ref(&self) -> &T {
/// The resulting lifetime is bound to self so this behaves "as if"
/// it were actually an instance of T that is getting borrowed. If a longer
/// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`.
+ ///
+ /// # Safety
+ ///
+ /// When calling this method, you have to ensure that all of the following is true:
+ /// - `self` is properly aligned
+ /// - `self` must point to an initialized instance of T; in particular, the pointer must be
+ /// "dereferenceable" in the sense defined [here].
+ ///
+ /// This applies even if the result of this method is unused!
+ /// (The part about being initialized is not yet fully decided, but until
+ /// it is the only safe approach is to ensure that they are indeed initialized.)
+ ///
+ /// Additionally, the lifetime of `self` does not necessarily reflect the actual
+ /// lifetime of the data. *You* must enforce Rust's aliasing rules. In particular,
+ /// for the duration of this lifetime, the memory this pointer points to must not
+ /// get accessed (read or written) through any other pointer.
+ ///
+ /// [here]: crate::ptr#safety
#[stable(feature = "nonnull", since = "1.25.0")]
#[inline]
pub unsafe fn as_mut(&mut self) -> &mut T {
unsafe { NonNull::new_unchecked(self.as_ptr().as_mut_ptr()) }
}
+ /// Returns a raw pointer to the slice's buffer.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// #![feature(slice_ptr_get, nonnull_slice_from_raw_parts)]
+ /// use std::ptr::NonNull;
+ ///
+ /// let slice: NonNull<[i8]> = NonNull::slice_from_raw_parts(NonNull::dangling(), 3);
+ /// assert_eq!(slice.as_mut_ptr(), 1 as *mut i8);
+ /// ```
+ #[inline]
+ #[unstable(feature = "slice_ptr_get", issue = "74265")]
+ #[rustc_const_unstable(feature = "slice_ptr_get", issue = "74265")]
+ pub const fn as_mut_ptr(self) -> *mut T {
+ self.as_non_null_ptr().as_ptr()
+ }
+
/// Returns a raw pointer to an element or subslice, without doing bounds
/// checking.
///
#[inline]
fn index(self, slice: &str) -> &Self::Output {
let (start, end) = (self.start, self.end);
- self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end))
+ match self.get(slice) {
+ Some(s) => s,
+ None => super::slice_error_fail(slice, start, end),
+ }
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
#[inline]
fn index(self, slice: &str) -> &Self::Output {
let end = self.end;
- self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, 0, end))
+ match self.get(slice) {
+ Some(s) => s,
+ None => super::slice_error_fail(slice, 0, end),
+ }
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
#[inline]
fn index(self, slice: &str) -> &Self::Output {
let (start, end) = (self.start, slice.len());
- self.get(slice).unwrap_or_else(|| super::slice_error_fail(slice, start, end))
+ match self.get(slice) {
+ Some(s) => s,
+ None => super::slice_error_fail(slice, start, end),
+ }
}
#[inline]
fn index_mut(self, slice: &mut str) -> &mut Self::Output {
/// nanosecond-level precision, APIs binding a system timeout will typically round up
/// the number of nanoseconds.
///
-/// `Duration`s implement many common traits, including [`Add`], [`Sub`], and other
-/// [`ops`] traits. It implements `Default` by returning a zero-length `Duration`.
+/// [`Duration`]s implement many common traits, including [`Add`], [`Sub`], and other
+/// [`ops`] traits. It implements [`Default`] by returning a zero-length `Duration`.
///
-/// [`Add`]: ../../std/ops/trait.Add.html
-/// [`Sub`]: ../../std/ops/trait.Sub.html
-/// [`ops`]: ../../std/ops/index.html
+/// [`ops`]: crate::ops
///
/// # Examples
///
/// + duration.subsec_nanos() as f64 * 1e-9);
/// ```
///
- /// [`subsec_nanos`]: #method.subsec_nanos
+ /// [`subsec_nanos`]: Duration::subsec_nanos
#[stable(feature = "duration", since = "1.3.0")]
#[rustc_const_stable(feature = "duration", since = "1.32.0")]
#[inline]
/// Checked `Duration` addition. Computes `self + other`, returning [`None`]
/// if overflow occurred.
///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
/// # Examples
///
/// Basic usage:
/// Checked `Duration` subtraction. Computes `self - other`, returning [`None`]
/// if the result would be negative or if overflow occurred.
///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
/// # Examples
///
/// Basic usage:
/// Checked `Duration` multiplication. Computes `self * other`, returning
/// [`None`] if overflow occurred.
///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
/// # Examples
///
/// Basic usage:
/// Checked `Duration` division. Computes `self / other`, returning [`None`]
/// if `other == 0`.
///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
/// # Examples
///
/// Basic usage:
} else if #[cfg(any(
all(target_family = "windows", target_env = "gnu"),
target_os = "cloudabi",
+ target_os = "psp",
target_family = "unix",
all(target_vendor = "fortanix", target_env = "sgx"),
))] {
// - os=uefi
// - nvptx64-nvidia-cuda
// - avr-unknown-unknown
- // - mipsel-sony-psp
#[path = "dummy.rs"]
mod real_imp;
}
compiler_builtins = { version = "0.1.32" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
-hashbrown = { version = "0.6.2", default-features = false, features = ['rustc-dep-of-std'] }
+hashbrown = { version = "0.8.1", default-features = false, features = ['rustc-dep-of-std'] }
# Dependencies of the `backtrace` crate
addr2line = { version = "0.13.0", optional = true, default-features = false }
#[inline]
#[unstable(feature = "try_reserve", reason = "new API", issue = "48043")]
pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> {
- self.base.try_reserve(additional).map_err(map_collection_alloc_err)
+ self.base.try_reserve(additional).map_err(map_try_reserve_error)
}
/// Shrinks the capacity of the map as much as possible. It will drop
{
self.base.retain(f)
}
+
+ /// Creates a consuming iterator visiting all the keys in arbitrary order.
+ /// The map cannot be used after calling this.
+ /// The iterator element type is `K`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_into_keys_values)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert("a", 1);
+ /// map.insert("b", 2);
+ /// map.insert("c", 3);
+ ///
+ /// let vec: Vec<&str> = map.into_keys().collect();
+ /// ```
+ #[inline]
+ #[unstable(feature = "map_into_keys_values", issue = "75294")]
+ pub fn into_keys(self) -> IntoKeys<K, V> {
+ IntoKeys { inner: self.into_iter() }
+ }
+
+ /// Creates a consuming iterator visiting all the values in arbitrary order.
+ /// The map cannot be used after calling this.
+ /// The iterator element type is `V`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(map_into_keys_values)]
+ /// use std::collections::HashMap;
+ ///
+ /// let mut map = HashMap::new();
+ /// map.insert("a", 1);
+ /// map.insert("b", 2);
+ /// map.insert("c", 3);
+ ///
+ /// let vec: Vec<i32> = map.into_values().collect();
+ /// ```
+ #[inline]
+ #[unstable(feature = "map_into_keys_values", issue = "75294")]
+ pub fn into_values(self) -> IntoValues<K, V> {
+ IntoValues { inner: self.into_iter() }
+ }
}
impl<K, V, S> HashMap<K, V, S>
inner: IterMut<'a, K, V>,
}
+/// An owning iterator over the keys of a `HashMap`.
+///
+/// This `struct` is created by the [`into_keys`] method on [`HashMap`].
+/// See its documentation for more.
+///
+/// [`into_keys`]: HashMap::into_keys
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+pub struct IntoKeys<K, V> {
+ inner: IntoIter<K, V>,
+}
+
+/// An owning iterator over the values of a `HashMap`.
+///
+/// This `struct` is created by the [`into_values`] method on [`HashMap`].
+/// See its documentation for more.
+///
+/// [`into_values`]: HashMap::into_values
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+pub struct IntoValues<K, V> {
+ inner: IntoIter<K, V>,
+}
+
/// A builder for computing where in a HashMap a key-value pair would be stored.
///
/// See the [`HashMap::raw_entry_mut`] docs for usage examples.
}
}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> Iterator for IntoKeys<K, V> {
+ type Item = K;
+
+ #[inline]
+ fn next(&mut self) -> Option<K> {
+ self.inner.next().map(|(k, _)| k)
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> FusedIterator for IntoKeys<K, V> {}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K: Debug, V: Debug> fmt::Debug for IntoKeys<K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish()
+ }
+}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> Iterator for IntoValues<K, V> {
+ type Item = V;
+
+ #[inline]
+ fn next(&mut self) -> Option<V> {
+ self.inner.next().map(|(_, v)| v)
+ }
+ #[inline]
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.inner.size_hint()
+ }
+}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> ExactSizeIterator for IntoValues<K, V> {
+ #[inline]
+ fn len(&self) -> usize {
+ self.inner.len()
+ }
+}
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V> FusedIterator for IntoValues<K, V> {}
+
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K: Debug, V: Debug> fmt::Debug for IntoValues<K, V> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish()
+ }
+}
+
#[stable(feature = "drain", since = "1.6.0")]
impl<'a, K, V> Iterator for Drain<'a, K, V> {
type Item = (K, V);
}
#[inline]
-fn map_collection_alloc_err(err: hashbrown::CollectionAllocErr) -> TryReserveError {
+fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError {
match err {
- hashbrown::CollectionAllocErr::CapacityOverflow => TryReserveError::CapacityOverflow,
- hashbrown::CollectionAllocErr::AllocErr { layout } => {
+ hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow,
+ hashbrown::TryReserveError::AllocError { layout } => {
TryReserveError::AllocError { layout, non_exhaustive: () }
}
}
assert!(values.contains(&6));
}
+ #[test]
+ fn test_into_keys() {
+ let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = vec.into_iter().collect();
+ let keys: Vec<_> = map.into_keys().collect();
+
+ assert_eq!(keys.len(), 3);
+ assert!(keys.contains(&1));
+ assert!(keys.contains(&2));
+ assert!(keys.contains(&3));
+ }
+
+ #[test]
+ fn test_into_values() {
+ let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')];
+ let map: HashMap<_, _> = vec.into_iter().collect();
+ let values: Vec<_> = map.into_values().collect();
+
+ assert_eq!(values.len(), 3);
+ assert!(values.contains(&'a'));
+ assert!(values.contains(&'b'));
+ assert!(values.contains(&'c'));
+ }
+
#[test]
fn test_find() {
let mut m = HashMap::new();
/// Capture a [closure]'s environment by value.
///
/// `move` converts any variables captured by reference or mutable reference
-/// to owned by value variables. The three [`Fn` trait]'s mirror the ways to capture
-/// variables, when `move` is used, the closures is represented by the `FnOnce` trait.
+/// to owned by value variables.
///
/// ```rust
/// let capture = "hello";
/// };
/// ```
///
+/// Note: `move` closures may still implement [`Fn`] or [`FnMut`], even though
+/// they capture variables by `move`. This is because the traits implemented by
+/// a closure type are determined by *what* the closure does with captured
+/// values, not *how* it captures them:
+///
+/// ```rust
+/// fn create_fn() -> impl Fn() {
+/// let text = "Fn".to_owned();
+///
+/// move || println!("This is a: {}", text)
+/// }
+///
+/// let fn_plain = create_fn();
+///
+/// fn_plain();
+/// ```
+///
/// `move` is often used when [threads] are involved.
///
/// ```rust
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_stable(feature = "const_ipv4", since = "1.32.0")]
pub const fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4Addr {
- // FIXME: should just be u32::from_be_bytes([a, b, c, d]),
- // once that method is no longer rustc_const_unstable
- Ipv4Addr {
- inner: c::in_addr {
- s_addr: u32::to_be(
- ((a as u32) << 24) | ((b as u32) << 16) | ((c as u32) << 8) | (d as u32),
- ),
- },
- }
+ // `s_addr` is stored as BE on all machine and the array is in BE order.
+ // So the native endian conversion method is used so that it's never swapped.
+ Ipv4Addr { inner: c::in_addr { s_addr: u32::from_ne_bytes([a, b, c, d]) } }
}
/// An IPv4 address with the address pointing to localhost: 127.0.0.1.
&self.inner
}
}
-impl FromInner<c::in_addr> for Ipv4Addr {
- fn from_inner(addr: c::in_addr) -> Ipv4Addr {
- Ipv4Addr { inner: addr }
- }
-}
#[stable(feature = "ip_u32", since = "1.1.0")]
impl From<Ipv4Addr> for u32 {
/// ```
/// use std::net::Ipv4Addr;
///
- /// let addr = Ipv4Addr::new(13, 12, 11, 10);
- /// assert_eq!(0x0d0c0b0au32, u32::from(addr));
+ /// let addr = Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe);
+ /// assert_eq!(0xcafebabe, u32::from(addr));
/// ```
fn from(ip: Ipv4Addr) -> u32 {
let ip = ip.octets();
/// ```
/// use std::net::Ipv4Addr;
///
- /// let addr = Ipv4Addr::from(0x0d0c0b0au32);
- /// assert_eq!(Ipv4Addr::new(13, 12, 11, 10), addr);
+ /// let addr = Ipv4Addr::from(0xcafebabe);
+ /// assert_eq!(Ipv4Addr::new(0xca, 0xfe, 0xba, 0xbe), addr);
/// ```
fn from(ip: u32) -> Ipv4Addr {
Ipv4Addr::from(ip.to_be_bytes())
//! * Executing a panic up to doing the actual implementation
//! * Shims around "try"
+#![deny(unsafe_op_in_unsafe_fn)]
+
use core::panic::{BoxMeUp, Location, PanicInfo};
use crate::any::Any;
let mut data = Data { f: ManuallyDrop::new(f) };
let data_ptr = &mut data as *mut _ as *mut u8;
- return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
- Ok(ManuallyDrop::into_inner(data.r))
- } else {
- Err(ManuallyDrop::into_inner(data.p))
- };
+ // SAFETY:
+ //
+ // Access to the union's fields: this is `std` and we know that the `r#try`
+ // intrinsic fills in the `r` or `p` union field based on its return value.
+ //
+ // The call to `intrinsics::r#try` is made safe by:
+ // - `do_call`, the first argument, can be called with the initial `data_ptr`.
+ // - `do_catch`, the second argument, can be called with the `data_ptr` as well.
+ // See their safety preconditions for more informations
+ unsafe {
+ return if intrinsics::r#try(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
+ Ok(ManuallyDrop::into_inner(data.r))
+ } else {
+ Err(ManuallyDrop::into_inner(data.p))
+ };
+ }
// We consider unwinding to be rare, so mark this function as cold. However,
// do not mark it no-inline -- that decision is best to leave to the
// non-cold function, though, as of the writing of this comment).
#[cold]
unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send + 'static> {
- let obj = Box::from_raw(__rust_panic_cleanup(payload));
+ // SAFETY: The whole unsafe block hinges on a correct implementation of
+ // the panic handler `__rust_panic_cleanup`. As such we can only
+ // assume it returns the correct thing for `Box::from_raw` to work
+ // without undefined behavior.
+ let obj = unsafe { Box::from_raw(__rust_panic_cleanup(payload)) };
panic_count::decrease();
obj
}
+ // SAFETY:
+ // data must be non-NUL, correctly aligned, and a pointer to a `Data<F, R>`
+ // Its must contains a valid `f` (type: F) value that can be use to fill
+ // `data.r`.
+ //
+ // This function cannot be marked as `unsafe` because `intrinsics::r#try`
+ // expects normal function pointers.
#[inline]
fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
+ // SAFETY: this is the responsibilty of the caller, see above.
unsafe {
let data = data as *mut Data<F, R>;
let data = &mut (*data);
// We *do* want this part of the catch to be inlined: this allows the
// compiler to properly track accesses to the Data union and optimize it
// away most of the time.
+ //
+ // SAFETY:
+ // data must be non-NUL, correctly aligned, and a pointer to a `Data<F, R>`
+ // Since this uses `cleanup` it also hinges on a correct implementation of
+ // `__rustc_panic_cleanup`.
+ //
+ // This function cannot be marked as `unsafe` because `intrinsics::r#try`
+ // expects normal function pointers.
#[inline]
fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
+ // SAFETY: this is the responsibilty of the caller, see above.
+ //
+ // When `__rustc_panic_cleaner` is correctly implemented we can rely
+ // on `obj` being the correct thing to pass to `data.p` (after wrapping
+ // in `ManuallyDrop`).
unsafe {
let data = data as *mut Data<F, R>;
let data = &mut (*data);
let loc = info.location().unwrap(); // The current implementation always returns Some
let msg = info.message().unwrap(); // The current implementation always returns Some
- rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+ crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
+ rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
+ })
}
/// This is the entry point of panicking for the non-format-string variants of
intrinsics::abort()
}
- rust_panic_with_hook(&mut PanicPayload::new(msg), None, Location::caller());
+ let loc = Location::caller();
+ return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
+ rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
+ });
struct PanicPayload<A> {
inner: Option<A>,
//! let path: PathBuf = ["c:\\", "windows", "system32.dll"].iter().collect();
//! ```
//!
-//! [`Component`]: ../../std/path/enum.Component.html
-//! [`components`]: ../../std/path/struct.Path.html#method.components
-//! [`PathBuf`]: ../../std/path/struct.PathBuf.html
-//! [`Path`]: ../../std/path/struct.Path.html
-//! [`push`]: ../../std/path/struct.PathBuf.html#method.push
-//! [`String`]: ../../std/string/struct.String.html
-//!
-//! [`str`]: ../../std/primitive.str.html
-//! [`OsString`]: ../../std/ffi/struct.OsString.html
-//! [`OsStr`]: ../../std/ffi/struct.OsStr.html
+//! [`components`]: Path::components
+//! [`push`]: PathBuf::push
#![stable(feature = "rust1", since = "1.0.0")]
/// # }
/// ```
///
-/// [`as_os_str`]: #method.as_os_str
-/// [`Component`]: enum.Component.html
-/// [`kind`]: #method.kind
-/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
-/// [`Prefix` variant]: enum.Component.html#variant.Prefix
-/// [`Prefix`]: enum.Prefix.html
+/// [`as_os_str`]: PrefixComponent::as_os_str
+/// [`kind`]: PrefixComponent::kind
+/// [`Prefix` variant]: Component::Prefix
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Copy, Clone, Eq, Debug)]
pub struct PrefixComponent<'a> {
///
/// See [`Prefix`]'s documentation for more information on the different
/// kinds of prefixes.
- ///
- /// [`Prefix`]: enum.Prefix.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn kind(&self) -> Prefix<'a> {
self.parsed
}
/// Returns the raw [`OsStr`] slice for this prefix.
- ///
- /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_os_str(&self) -> &'a OsStr {
self.raw
/// Component::Normal("bar.txt".as_ref()),
/// ]);
/// ```
-///
-/// [`Components`]: struct.Components.html
-/// [`Path`]: struct.Path.html
-/// [`Path::components`]: struct.Path.html#method.components
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Component<'a> {
/// for more.
///
/// Does not occur on Unix.
- ///
- /// [`Prefix`]: enum.Prefix.html
#[stable(feature = "rust1", since = "1.0.0")]
Prefix(#[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a>),
/// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect();
/// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
/// ```
- ///
- /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub fn as_os_str(self) -> &'a OsStr {
match self {
/// }
/// ```
///
-/// [`Component`]: enum.Component.html
-/// [`components`]: struct.Path.html#method.components
-/// [`Path`]: struct.Path.html
+/// [`components`]: Path::components
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Components<'a> {
/// This `struct` is created by the [`iter`] method on [`Path`].
/// See its documentation for more.
///
-/// [`Component`]: enum.Component.html
-/// [`iter`]: struct.Path.html#method.iter
-/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
-/// [`Path`]: struct.Path.html
+/// [`iter`]: Path::iter
#[derive(Clone)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Iter<'a> {
/// }
/// ```
///
-/// [`ancestors`]: struct.Path.html#method.ancestors
-/// [`Path`]: struct.Path.html
+/// [`ancestors`]: Path::ancestors
#[derive(Copy, Clone, Debug)]
#[stable(feature = "path_ancestors", since = "1.28.0")]
pub struct Ancestors<'a> {
/// the path in place. It also implements [`Deref`] to [`Path`], meaning that
/// all methods on [`Path`] slices are available on `PathBuf` values as well.
///
-/// [`String`]: ../string/struct.String.html
-/// [`Path`]: struct.Path.html
-/// [`push`]: struct.PathBuf.html#method.push
-/// [`set_extension`]: struct.PathBuf.html#method.set_extension
-/// [`Deref`]: ../ops/trait.Deref.html
+/// [`push`]: PathBuf::push
+/// [`set_extension`]: PathBuf::set_extension
///
/// More details about the overall approach can be found in
/// the [module documentation](index.html).
/// assert_eq!(capacity, path.capacity());
/// ```
///
- /// [`with_capacity`]: ../ffi/struct.OsString.html#method.with_capacity
- /// [`OsString`]: ../ffi/struct.OsString.html
+ /// [`with_capacity`]: OsString::with_capacity
#[stable(feature = "path_buf_capacity", since = "1.44.0")]
pub fn with_capacity(capacity: usize) -> PathBuf {
PathBuf { inner: OsString::with_capacity(capacity) }
/// Coerces to a [`Path`] slice.
///
- /// [`Path`]: struct.Path.html
- ///
/// # Examples
///
/// ```
/// Returns `false` and does nothing if [`self.parent`] is [`None`].
/// Otherwise, returns `true`.
///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- /// [`self.parent`]: struct.PathBuf.html#method.parent
+ /// [`self.parent`]: Path::parent
///
/// # Examples
///
/// ```
/// use std::path::{Path, PathBuf};
///
- /// let mut p = PathBuf::from("/test/test.rs");
+ /// let mut p = PathBuf::from("/spirited/away.rs");
///
/// p.pop();
- /// assert_eq!(Path::new("/test"), p);
+ /// assert_eq!(Path::new("/spirited"), p);
/// p.pop();
/// assert_eq!(Path::new("/"), p);
/// ```
/// `file_name`. The new path will be a sibling of the original path.
/// (That is, it will have the same parent.)
///
- /// [`self.file_name`]: struct.PathBuf.html#method.file_name
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- /// [`pop`]: struct.PathBuf.html#method.pop
+ /// [`self.file_name`]: Path::file_name
+ /// [`pop`]: PathBuf::pop
///
/// # Examples
///
/// If [`self.extension`] is [`None`], the extension is added; otherwise
/// it is replaced.
///
- /// [`self.file_name`]: struct.PathBuf.html#method.file_name
- /// [`self.extension`]: struct.PathBuf.html#method.extension
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`self.file_name`]: Path::file_name
+ /// [`self.extension`]: Path::extension
///
/// # Examples
///
/// Consumes the `PathBuf`, yielding its internal [`OsString`] storage.
///
- /// [`OsString`]: ../ffi/struct.OsString.html
- ///
/// # Examples
///
/// ```
}
/// Converts this `PathBuf` into a [boxed][`Box`] [`Path`].
- ///
- /// [`Box`]: ../../std/boxed/struct.Box.html
- /// [`Path`]: struct.Path.html
#[stable(feature = "into_boxed_path", since = "1.20.0")]
pub fn into_boxed_path(self) -> Box<Path> {
let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path;
/// Invokes [`capacity`] on the underlying instance of [`OsString`].
///
- /// [`capacity`]: ../ffi/struct.OsString.html#method.capacity
- /// [`OsString`]: ../ffi/struct.OsString.html
+ /// [`capacity`]: OsString::capacity
#[stable(feature = "path_buf_capacity", since = "1.44.0")]
pub fn capacity(&self) -> usize {
self.inner.capacity()
/// Invokes [`clear`] on the underlying instance of [`OsString`].
///
- /// [`clear`]: ../ffi/struct.OsString.html#method.clear
- /// [`OsString`]: ../ffi/struct.OsString.html
+ /// [`clear`]: OsString::clear
#[stable(feature = "path_buf_capacity", since = "1.44.0")]
pub fn clear(&mut self) {
self.inner.clear()
/// Invokes [`reserve`] on the underlying instance of [`OsString`].
///
- /// [`reserve`]: ../ffi/struct.OsString.html#method.reserve
- /// [`OsString`]: ../ffi/struct.OsString.html
+ /// [`reserve`]: OsString::reserve
#[stable(feature = "path_buf_capacity", since = "1.44.0")]
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional)
/// Invokes [`reserve_exact`] on the underlying instance of [`OsString`].
///
- /// [`reserve_exact`]: ../ffi/struct.OsString.html#method.reserve_exact
- /// [`OsString`]: ../ffi/struct.OsString.html
+ /// [`reserve_exact`]: OsString::reserve_exact
#[stable(feature = "path_buf_capacity", since = "1.44.0")]
pub fn reserve_exact(&mut self, additional: usize) {
self.inner.reserve_exact(additional)
/// Invokes [`shrink_to_fit`] on the underlying instance of [`OsString`].
///
- /// [`shrink_to_fit`]: ../ffi/struct.OsString.html#method.shrink_to_fit
- /// [`OsString`]: ../ffi/struct.OsString.html
+ /// [`shrink_to_fit`]: OsString::shrink_to_fit
#[stable(feature = "path_buf_capacity", since = "1.44.0")]
pub fn shrink_to_fit(&mut self) {
self.inner.shrink_to_fit()
/// Invokes [`shrink_to`] on the underlying instance of [`OsString`].
///
- /// [`shrink_to`]: ../ffi/struct.OsString.html#method.shrink_to
- /// [`OsString`]: ../ffi/struct.OsString.html
+ /// [`shrink_to`]: OsString::shrink_to
#[unstable(feature = "shrink_to", issue = "56431")]
pub fn shrink_to(&mut self, min_capacity: usize) {
self.inner.shrink_to(min_capacity)
/// pointer like `&` or [`Box`]. For an owned version of this type,
/// see [`PathBuf`].
///
-/// [`str`]: ../primitive.str.html
-/// [`Box`]: ../boxed/struct.Box.html
-/// [`PathBuf`]: struct.PathBuf.html
-///
/// More details about the overall approach can be found in
/// the [module documentation](index.html).
///
/// This `struct` is created by the [`strip_prefix`] method on [`Path`].
/// See its documentation for more.
///
-/// [`strip_prefix`]: struct.Path.html#method.strip_prefix
-/// [`Path`]: struct.Path.html
+/// [`strip_prefix`]: Path::strip_prefix
#[derive(Debug, Clone, PartialEq, Eq)]
#[stable(since = "1.7.0", feature = "strip_prefix")]
pub struct StripPrefixError(());
/// Yields the underlying [`OsStr`] slice.
///
- /// [`OsStr`]: ../ffi/struct.OsStr.html
- ///
/// # Examples
///
/// ```
/// Note that validation is performed because non-UTF-8 strings are
/// perfectly valid for some OS.
///
- /// [`&str`]: ../primitive.str.html
+ /// [`&str`]: str
///
/// # Examples
///
/// Any non-Unicode sequences are replaced with
/// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
///
- /// [`Cow<str>`]: ../borrow/enum.Cow.html
- /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html
+ /// [`Cow<str>`]: Cow
+ /// [U+FFFD]: super::char::REPLACEMENT_CHARACTER
///
/// # Examples
///
/// Converts a `Path` to an owned [`PathBuf`].
///
- /// [`PathBuf`]: struct.PathBuf.html
- ///
/// # Examples
///
/// ```
/// assert!(!Path::new("foo.txt").is_absolute());
/// ```
///
- /// [`has_root`]: #method.has_root
+ /// [`has_root`]: Path::has_root
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(deprecated)]
pub fn is_absolute(&self) -> bool {
/// assert!(Path::new("foo.txt").is_relative());
/// ```
///
- /// [`is_absolute`]: #method.is_absolute
+ /// [`is_absolute`]: Path::is_absolute
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_relative(&self) -> bool {
!self.is_absolute()
///
/// Returns [`None`] if the path terminates in a root or prefix.
///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
/// # Examples
///
/// ```
/// assert_eq!(ancestors.next(), Some(Path::new("/foo")));
/// assert_eq!(ancestors.next(), Some(Path::new("/")));
/// assert_eq!(ancestors.next(), None);
+ ///
+ /// let mut ancestors = Path::new("../foo/bar").ancestors();
+ /// assert_eq!(ancestors.next(), Some(Path::new("../foo/bar")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("../foo")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("..")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("")));
+ /// assert_eq!(ancestors.next(), None);
/// ```
///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- /// [`parent`]: struct.Path.html#method.parent
+ /// [`parent`]: Path::parent
#[stable(feature = "path_ancestors", since = "1.28.0")]
pub fn ancestors(&self) -> Ancestors<'_> {
Ancestors { next: Some(&self) }
///
/// Returns [`None`] if the path terminates in `..`.
///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
/// # Examples
///
/// ```
/// If `base` is not a prefix of `self` (i.e., [`starts_with`]
/// returns `false`), returns [`Err`].
///
- /// [`starts_with`]: #method.starts_with
- /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`starts_with`]: Path::starts_with
///
/// # Examples
///
/// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt")));
/// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new("")));
/// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
- /// assert_eq!(path.strip_prefix("test").is_ok(), false);
- /// assert_eq!(path.strip_prefix("/haha").is_ok(), false);
+ ///
+ /// assert!(path.strip_prefix("test").is_err());
+ /// assert!(path.strip_prefix("/haha").is_err());
///
/// let prefix = PathBuf::from("/test/");
/// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt")));
/// assert!(path.starts_with("/etc"));
/// assert!(path.starts_with("/etc/"));
/// assert!(path.starts_with("/etc/passwd"));
- /// assert!(path.starts_with("/etc/passwd/"));
+ /// assert!(path.starts_with("/etc/passwd/")); // extra slash is okay
+ /// assert!(path.starts_with("/etc/passwd///")); // multiple extra slashes are okay
///
/// assert!(!path.starts_with("/e"));
+ /// assert!(!path.starts_with("/etc/passwd.txt"));
+ ///
+ /// assert!(!Path::new("/etc/foo.rs").starts_with("/etc/foo"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
/// Extracts the stem (non-extension) portion of [`self.file_name`].
///
- /// [`self.file_name`]: struct.Path.html#method.file_name
+ /// [`self.file_name`]: Path::file_name
///
/// The stem is:
///
/// * The entire file name if the file name begins with `.` and has no other `.`s within;
/// * Otherwise, the portion of the file name before the final `.`
///
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
- ///
/// # Examples
///
/// ```
/// use std::path::Path;
///
- /// let path = Path::new("foo.rs");
- ///
- /// assert_eq!("foo", path.file_stem().unwrap());
+ /// assert_eq!("foo", Path::new("foo.rs").file_stem().unwrap());
+ /// assert_eq!("foo.tar", Path::new("foo.tar.gz").file_stem().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn file_stem(&self) -> Option<&OsStr> {
/// * [`None`], if the file name begins with `.` and has no other `.`s within;
/// * Otherwise, the portion of the file name after the final `.`
///
- /// [`self.file_name`]: struct.Path.html#method.file_name
- /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`self.file_name`]: Path::file_name
///
/// # Examples
///
/// ```
/// use std::path::Path;
///
- /// let path = Path::new("foo.rs");
- ///
- /// assert_eq!("rs", path.extension().unwrap());
+ /// assert_eq!("rs", Path::new("foo.rs").extension().unwrap());
+ /// assert_eq!("gz", Path::new("foo.tar.gz").extension().unwrap());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn extension(&self) -> Option<&OsStr> {
///
/// See [`PathBuf::push`] for more details on what it means to adjoin a path.
///
- /// [`PathBuf`]: struct.PathBuf.html
- /// [`PathBuf::push`]: struct.PathBuf.html#method.push
- ///
/// # Examples
///
/// ```
///
/// See [`PathBuf::set_file_name`] for more details.
///
- /// [`PathBuf`]: struct.PathBuf.html
- /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name
- ///
/// # Examples
///
/// ```
///
/// See [`PathBuf::set_extension`] for more details.
///
- /// [`PathBuf`]: struct.PathBuf.html
- /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension
- ///
/// # Examples
///
/// ```
///
/// let path = Path::new("foo.tar.gz");
/// assert_eq!(path.with_extension(""), PathBuf::from("foo.tar"));
+ /// assert_eq!(path.with_extension("xz"), PathBuf::from("foo.tar.xz"));
+ /// assert_eq!(path.with_extension("").with_extension("txt"), PathBuf::from("foo.txt"));
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
/// assert_eq!(components.next(), None)
/// ```
///
- /// [`Component`]: enum.Component.html
- /// [`CurDir`]: enum.Component.html#variant.CurDir
+ /// [`CurDir`]: Component::CurDir
#[stable(feature = "rust1", since = "1.0.0")]
pub fn components(&self) -> Components<'_> {
let prefix = parse_prefix(self.as_os_str());
/// For more information about the particulars of how the path is separated
/// into components, see [`components`].
///
- /// [`components`]: #method.components
- /// [`OsStr`]: ../ffi/struct.OsStr.html
+ /// [`components`]: Path::components
///
/// # Examples
///
/// Returns an object that implements [`Display`] for safely printing paths
/// that may contain non-Unicode data.
///
- /// [`Display`]: ../fmt/trait.Display.html
+ /// [`Display`]: fmt::Display
///
/// # Examples
///
///
/// This is an alias to [`fs::metadata`].
///
- /// [`fs::metadata`]: ../fs/fn.metadata.html
- ///
/// # Examples
///
/// ```no_run
///
/// This is an alias to [`fs::symlink_metadata`].
///
- /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html
- ///
/// # Examples
///
/// ```no_run
///
/// This is an alias to [`fs::canonicalize`].
///
- /// [`fs::canonicalize`]: ../fs/fn.canonicalize.html
- ///
/// # Examples
///
/// ```no_run
///
/// This is an alias to [`fs::read_link`].
///
- /// [`fs::read_link`]: ../fs/fn.read_link.html
- ///
/// # Examples
///
/// ```no_run
/// Returns an iterator over the entries within a directory.
///
- /// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. New
+ /// The iterator will yield instances of [`io::Result`]`<`[`fs::DirEntry`]`>`. New
/// errors may be encountered after an iterator is initially constructed.
///
/// This is an alias to [`fs::read_dir`].
///
- /// [`io::Result`]: ../io/type.Result.html
- /// [`DirEntry`]: ../fs/struct.DirEntry.html
- /// [`fs::read_dir`]: ../fs/fn.read_dir.html
- ///
/// # Examples
///
/// ```no_run
///
/// ```no_run
/// use std::path::Path;
- /// assert_eq!(Path::new("does_not_exist.txt").exists(), false);
+ /// assert!(!Path::new("does_not_exist.txt").exists());
/// ```
///
/// # See Also
///
/// This is a convenience function that coerces errors to false. If you want to
- /// check errors, call [fs::metadata].
- ///
- /// [fs::metadata]: ../../std/fs/fn.metadata.html
+ /// check errors, call [`fs::metadata`].
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn exists(&self) -> bool {
fs::metadata(self).is_ok()
/// # See Also
///
/// This is a convenience function that coerces errors to false. If you want to
- /// check errors, call [`fs::metadata`] and handle its Result. Then call
- /// [`fs::Metadata::is_file`] if it was Ok.
+ /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
+ /// [`fs::Metadata::is_file`] if it was [`Ok`].
///
/// When the goal is simply to read from (or write to) the source, the most
/// reliable way to test the source can be read (or written to) is to open
/// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
- /// a Unix-like system for example. See [`File::open`] or
- /// [`OpenOptions::open`] for more information.
- ///
- /// [`fs::metadata`]: ../../std/fs/fn.metadata.html
- /// [`fs::Metadata`]: ../../std/fs/struct.Metadata.html
- /// [`fs::Metadata::is_file`]: ../../std/fs/struct.Metadata.html#method.is_file
- /// [`File::open`]: ../../std/fs/struct.File.html#method.open
- /// [`OpenOptions::open`]: ../../std/fs/struct.OpenOptions.html#method.open
+ /// a Unix-like system for example. See [`fs::File::open`] or
+ /// [`fs::OpenOptions::open`] for more information.
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn is_file(&self) -> bool {
fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
/// # See Also
///
/// This is a convenience function that coerces errors to false. If you want to
- /// check errors, call [fs::metadata] and handle its Result. Then call
- /// [fs::Metadata::is_dir] if it was Ok.
- ///
- /// [fs::metadata]: ../../std/fs/fn.metadata.html
- /// [fs::Metadata::is_dir]: ../../std/fs/struct.Metadata.html#method.is_dir
+ /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
+ /// [`fs::Metadata::is_dir`] if it was [`Ok`].
#[stable(feature = "path_ext", since = "1.5.0")]
pub fn is_dir(&self) -> bool {
fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
/// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or
/// allocating.
- ///
- /// [`Box`]: ../../std/boxed/struct.Box.html
- /// [`PathBuf`]: struct.PathBuf.html
#[stable(feature = "into_boxed_path", since = "1.20.0")]
pub fn into_path_buf(self: Box<Path>) -> PathBuf {
let rw = Box::into_raw(self) as *mut OsStr;
/// println!("{}", path.display());
/// ```
///
-/// [`Display`]: ../../std/fmt/trait.Display.html
-/// [`format!`]: ../../std/macro.format.html
-/// [`Path`]: struct.Path.html
-/// [`Path::display`]: struct.Path.html#method.display
+/// [`Display`]: fmt::Display
+/// [`format!`]: crate::format
#[stable(feature = "rust1", since = "1.0.0")]
pub struct Display<'a> {
path: &'a Path,
sys::args::init(argc, argv);
// Let's run some code!
- let exit_code = panic::catch_unwind(|| {
- sys_common::backtrace::__rust_begin_short_backtrace(move || main())
- });
+ let exit_code = panic::catch_unwind(main);
sys_common::cleanup();
exit_code.unwrap_or(101) as isize
argc: isize,
argv: *const *const u8,
) -> isize {
- lang_start_internal(&move || main().report(), argc, argv)
+ lang_start_internal(
+ &move || crate::sys_common::backtrace::__rust_begin_short_backtrace(main).report(),
+ argc,
+ argv,
+ )
}
argv: *const *const c_char,
env: *const *const c_char,
) -> ! {
- use crate::sys::hermit::fast_thread_local::run_dtors;
+ use crate::sys::hermit::thread_local_dtor::run_dtors;
extern "C" {
fn main(argc: isize, argv: *const *const c_char) -> i32;
}
use crate::io;
use crate::mem;
use crate::sys::hermit::abi;
-use crate::sys::hermit::fast_thread_local::run_dtors;
+use crate::sys::hermit::thread_local_dtor::run_dtors;
use crate::time::Duration;
pub type Tid = abi::Tid;
#[cfg(test)]
mod tests {
use super::{FileDesc, IoSlice};
+ use core::mem::ManuallyDrop;
#[test]
fn limit_vector_count() {
- let stdout = FileDesc { fd: 1 };
+ let stdout = ManuallyDrop::new(FileDesc { fd: 1 });
let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::<Vec<_>>();
-
assert!(stdout.write_vectored(&bufs).is_ok());
}
}
pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> {
let ptr = haystack.as_ptr();
- let mut len = haystack.len();
let mut start = &haystack[..];
// For performance reasons unfold the loop eight times.
- while len >= 8 {
- if start[0] == needle {
- return Some((start.as_ptr() as usize - ptr as usize) / 2);
- }
- if start[1] == needle {
- return Some((start[1..].as_ptr() as usize - ptr as usize) / 2);
- }
- if start[2] == needle {
- return Some((start[2..].as_ptr() as usize - ptr as usize) / 2);
- }
- if start[3] == needle {
- return Some((start[3..].as_ptr() as usize - ptr as usize) / 2);
- }
- if start[4] == needle {
- return Some((start[4..].as_ptr() as usize - ptr as usize) / 2);
- }
- if start[5] == needle {
- return Some((start[5..].as_ptr() as usize - ptr as usize) / 2);
- }
- if start[6] == needle {
- return Some((start[6..].as_ptr() as usize - ptr as usize) / 2);
- }
- if start[7] == needle {
- return Some((start[7..].as_ptr() as usize - ptr as usize) / 2);
+ while start.len() >= 8 {
+ macro_rules! if_return {
+ ($($n:literal,)+) => {
+ $(
+ if start[$n] == needle {
+ return Some((&start[$n] as *const u16 as usize - ptr as usize) / 2);
+ }
+ )+
+ }
}
+ if_return!(0, 1, 2, 3, 4, 5, 6, 7,);
+
start = &start[8..];
- len -= 8;
}
- for (i, c) in start.iter().enumerate() {
+ for c in start {
if *c == needle {
- return Some((start.as_ptr() as usize - ptr as usize) / 2 + i);
+ return Some((c as *const u16 as usize - ptr as usize) / 2);
}
}
None
bt_fmt.add_context()?;
let mut idx = 0;
let mut res = Ok(());
+ // Start immediately if we're not using a short backtrace.
+ let mut start = print_fmt != PrintFmt::Short;
backtrace_rs::trace_unsynchronized(|frame| {
if print_fmt == PrintFmt::Short && idx > MAX_NB_FRAMES {
return false;
stop = true;
return;
}
+ if sym.contains("__rust_end_short_backtrace") {
+ start = true;
+ return;
+ }
}
}
- res = bt_fmt.frame().symbol(frame, symbol);
+ if start {
+ res = bt_fmt.frame().symbol(frame, symbol);
+ }
});
if stop {
return false;
}
if !hit {
- res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
+ if start {
+ res = bt_fmt.frame().print_raw(frame.ip(), None, None, None);
+ }
}
idx += 1;
pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
where
F: FnOnce() -> T,
- F: Send,
- T: Send,
{
- f()
+ let result = f();
+
+ // prevent this frame from being tail-call optimised away
+ crate::hint::black_box(());
+
+ result
+}
+
+/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. Note that
+/// this is only inline(never) when backtraces in libstd are enabled, otherwise
+/// it's fine to optimize away.
+#[cfg_attr(feature = "backtrace", inline(never))]
+pub fn __rust_end_short_backtrace<F, T>(f: F) -> T
+where
+ F: FnOnce() -> T,
+{
+ let result = f();
+
+ // prevent this frame from being tail-call optimised away
+ crate::hint::black_box(());
+
+ result
}
pub enum RustBacktrace {
static __KEY: $crate::thread::__OsLocalKeyInner<$t> =
$crate::thread::__OsLocalKeyInner::new();
- __KEY.get(__init)
+ // FIXME: remove the #[allow(...)] marker when macros don't
+ // raise warning for missing/extraneous unsafe blocks anymore.
+ // See https://github.com/rust-lang/rust/issues/74838.
+ #[allow(unused_unsafe)]
+ unsafe { __KEY.get(__init) }
}
unsafe {
#[allow(deprecated)]
pub fn get_concurrency() -> usize {
- return match env::var("RUST_TEST_THREADS") {
+ match env::var("RUST_TEST_THREADS") {
Ok(s) => {
let opt_n: Option<usize> = s.parse().ok();
match opt_n {
}
}
Err(..) => num_cpus(),
- };
+ }
}
cfg_if::cfg_if! {
/// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`.
#[inline(never)]
fn __rust_begin_short_backtrace<F: FnOnce()>(f: F) {
- f()
+ f();
+
+ // prevent this frame from being tail-call optimised away
+ black_box(());
}
fn run_test_in_process(
} else if #[cfg(any(
unix,
windows,
+ target_os = "psp",
target_os = "cloudabi",
all(target_vendor = "fortanix", target_env = "sgx"),
))] {
// - os=uefi
// - os=cuda
// - nvptx64-nvidia-cuda
- // - mipsel-sony-psp
// - Any new targets not listed above.
}
}
ctrl = table["ctrl"]["pointer"]
self.size = int(table["items"])
- self.data_ptr = table["data"]["pointer"]
- self.pair_type = self.data_ptr.dereference().type
+ self.pair_type = table.type.template_argument(0)
+
+ self.new_layout = not table.type.has_key("data")
+ if self.new_layout:
+ self.data_ptr = ctrl.cast(self.pair_type.pointer())
+ else:
+ self.data_ptr = table["data"]["pointer"]
self.valid_indices = []
for idx in range(capacity):
for index in range(self.size):
idx = self.valid_indices[index]
+ if self.new_layout:
+ idx = -(idx + 1)
element = (pairs_start + idx).dereference()
if self.show_values:
yield "key{}".format(index), element[ZERO_FIELD]
# type: (int) -> SBValue
pairs_start = self.data_ptr.GetValueAsUnsigned()
idx = self.valid_indices[index]
+ if self.new_layout:
+ idx = -(idx + 1)
address = pairs_start + idx * self.pair_type_size
element = self.data_ptr.CreateValueFromAddress("[%s]" % index, address, self.pair_type)
if self.show_values:
ctrl = table.GetChildMemberWithName("ctrl").GetChildAtIndex(0)
self.size = table.GetChildMemberWithName("items").GetValueAsUnsigned()
- self.data_ptr = table.GetChildMemberWithName("data").GetChildAtIndex(0)
- self.pair_type = self.data_ptr.Dereference().GetType()
+ self.pair_type = table.type.template_args[0]
self.pair_type_size = self.pair_type.GetByteSize()
+ self.new_layout = not table.GetChildMemberWithName("data").IsValid()
+ if self.new_layout:
+ self.data_ptr = ctrl.Cast(self.pair_type.GetPointerType())
+ else:
+ self.data_ptr = table.GetChildMemberWithName("data").GetChildAtIndex(0)
+
u8_type = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar)
u8_type_size = self.valobj.GetTarget().GetBasicType(eBasicTypeUnsignedChar).GetByteSize()
<Expand>
<Item Name="[size]">base.table.items</Item>
<Item Name="[capacity]">base.table.items + base.table.growth_left</Item>
+ <Item Name="[state]">base.hash_builder</Item>
<CustomListItems>
<Variable Name="i" InitialValue="0" />
<If Condition="(base.table.ctrl.pointer[i] & 0x80) == 0">
<!-- Bucket is populated -->
<Exec>n--</Exec>
- <Item Name="{base.table.data.pointer[i].__0}">base.table.data.pointer[i].__1</Item>
+ <Item Name="{static_cast<tuple<$T1, $T2>*>(base.table.ctrl.pointer)[-(i + 1)].__0}">static_cast<tuple<$T1, $T2>*>(base.table.ctrl.pointer)[-(i + 1)].__1</Item>
</If>
<Exec>i++</Exec>
</Loop>
<Expand>
<Item Name="[size]">map.base.table.items</Item>
<Item Name="[capacity]">map.base.table.items + map.base.table.growth_left</Item>
+ <Item Name="[state]">map.base.hash_builder</Item>
<CustomListItems>
<Variable Name="i" InitialValue="0" />
<If Condition="(map.base.table.ctrl.pointer[i] & 0x80) == 0">
<!-- Bucket is populated -->
<Exec>n--</Exec>
- <Item>map.base.table.data.pointer[i].__0</Item>
- </If>
- <Exec>i++</Exec>
- </Loop>
- </CustomListItems>
- </Expand>
- </Type>
-
- <Type Name="hashbrown::raw::RawTable<*>">
- <!-- RawTable has a nice and simple layout.
- items Number of *populated* values in the RawTable (less than the size of ctrl.pointer / data.pointer)
- growth_left Remaining capacity before growth
- ctrl.pointer[i] & 0x80 Indicates the bucket is empty / should be skipped / doesn't count towards items.
- data.pointer[i] The (K,V) tuple, if not empty.
- -->
- <DisplayString>{{ size={items} }}</DisplayString>
- <Expand>
- <Item Name="[size]">items</Item>
- <Item Name="[capacity]">items + growth_left</Item>
-
- <CustomListItems>
- <Variable Name="i" InitialValue="0" />
- <Variable Name="n" InitialValue="items" />
- <Size>items</Size>
- <Loop>
- <Break Condition="n == 0" />
- <If Condition="(ctrl.pointer[i] & 0x80) == 0">
- <!-- Bucket is populated -->
- <Exec>n--</Exec>
- <Item>data.pointer[i]</Item>
+ <Item>static_cast<$T1*>(map.base.table.ctrl.pointer)[-(i + 1)]</Item>
</If>
<Exec>i++</Exec>
</Loop>
[dependencies]
rustc_serialize = { path = "../librustc_serialize" }
log = { package = "tracing", version = "0.1" }
-scoped-tls = "1.0"
rustc_span = { path = "../librustc_span" }
rustc_data_structures = { path = "../librustc_data_structures" }
rustc_index = { path = "../librustc_index" }
pub use UnsafeSource::*;
use crate::ptr::P;
-use crate::token::{self, DelimToken};
+use crate::token::{self, CommentKind, DelimToken};
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct WhereClause {
/// `true` if we ate a `where` token: this can happen
- /// if we parsed no predicates (e.g. `struct Foo where {}
+ /// if we parsed no predicates (e.g. `struct Foo where {}`).
/// This allows us to accurately pretty-print
/// in `nt_to_tokenstream`
pub has_where_token: bool,
}
}
+ /// Is this expr either `N`, or `{ N }`.
+ ///
+ /// If this is not the case, name resolution does not resolve `N` when using
+ /// `feature(min_const_generics)` as more complex expressions are not supported.
+ pub fn is_potential_trivial_const_param(&self) -> bool {
+ let this = if let ExprKind::Block(ref block, None) = self.kind {
+ if block.stmts.len() == 1 {
+ if let StmtKind::Expr(ref expr) = block.stmts[0].kind { expr } else { self }
+ } else {
+ self
+ }
+ } else {
+ self
+ };
+
+ if let ExprKind::Path(None, ref path) = this.kind {
+ if path.segments.len() == 1 && path.segments[0].args.is_none() {
+ return true;
+ }
+ }
+
+ false
+ }
+
pub fn to_bound(&self) -> Option<GenericBound> {
match &self.kind {
ExprKind::Path(None, path) => Some(GenericBound::Trait(
/// A doc comment (e.g. `/// ...`, `//! ...`, `/** ... */`, `/*! ... */`).
/// Doc attributes (e.g. `#[doc="..."]`) are represented with the `Normal`
/// variant (which is much less compact and thus more expensive).
- DocComment(Symbol),
+ DocComment(CommentKind, Symbol),
}
/// `TraitRef`s appear in impls.
use crate::ast::{Path, PathSegment};
use crate::mut_visit::visit_clobber;
use crate::ptr::P;
-use crate::token::{self, Token};
+use crate::token::{self, CommentKind, Token};
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint};
-use rustc_data_structures::sync::Lock;
use rustc_index::bit_set::GrowableBitSet;
-use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::source_map::{BytePos, Spanned};
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
-use log::debug;
use std::iter;
use std::ops::DerefMut;
-// Per-session global variables: this struct is stored in thread-local storage
-// in such a way that it is accessible without any kind of handle to all
-// threads within the compilation session, but is not accessible outside the
-// session.
-pub struct SessionGlobals {
- used_attrs: Lock<GrowableBitSet<AttrId>>,
- known_attrs: Lock<GrowableBitSet<AttrId>>,
- span_session_globals: rustc_span::SessionGlobals,
-}
+pub struct MarkedAttrs(GrowableBitSet<AttrId>);
-impl SessionGlobals {
- fn new(edition: Edition) -> SessionGlobals {
- SessionGlobals {
- // We have no idea how many attributes there will be, so just
- // initiate the vectors with 0 bits. We'll grow them as necessary.
- used_attrs: Lock::new(GrowableBitSet::new_empty()),
- known_attrs: Lock::new(GrowableBitSet::new_empty()),
- span_session_globals: rustc_span::SessionGlobals::new(edition),
- }
+impl MarkedAttrs {
+ // We have no idea how many attributes there will be, so just
+ // initiate the vectors with 0 bits. We'll grow them as necessary.
+ pub fn new() -> Self {
+ MarkedAttrs(GrowableBitSet::new_empty())
}
-}
-
-pub fn with_session_globals<R>(edition: Edition, f: impl FnOnce() -> R) -> R {
- let ast_session_globals = SessionGlobals::new(edition);
- SESSION_GLOBALS.set(&ast_session_globals, || {
- rustc_span::SESSION_GLOBALS.set(&ast_session_globals.span_session_globals, f)
- })
-}
-
-pub fn with_default_session_globals<R>(f: impl FnOnce() -> R) -> R {
- with_session_globals(DEFAULT_EDITION, f)
-}
-scoped_tls::scoped_thread_local!(pub static SESSION_GLOBALS: SessionGlobals);
-
-pub fn mark_used(attr: &Attribute) {
- debug!("marking {:?} as used", attr);
- SESSION_GLOBALS.with(|session_globals| {
- session_globals.used_attrs.lock().insert(attr.id);
- });
-}
-
-pub fn is_used(attr: &Attribute) -> bool {
- SESSION_GLOBALS.with(|session_globals| session_globals.used_attrs.lock().contains(attr.id))
-}
-
-pub fn mark_known(attr: &Attribute) {
- debug!("marking {:?} as known", attr);
- SESSION_GLOBALS.with(|session_globals| {
- session_globals.known_attrs.lock().insert(attr.id);
- });
-}
+ pub fn mark(&mut self, attr: &Attribute) {
+ self.0.insert(attr.id);
+ }
-pub fn is_known(attr: &Attribute) -> bool {
- SESSION_GLOBALS.with(|session_globals| session_globals.known_attrs.lock().contains(attr.id))
+ pub fn is_marked(&self, attr: &Attribute) -> bool {
+ self.0.contains(attr.id)
+ }
}
pub fn is_known_lint_tool(m_item: Ident) -> bool {
pub fn has_name(&self, name: Symbol) -> bool {
match self.kind {
AttrKind::Normal(ref item) => item.path == name,
- AttrKind::DocComment(_) => false,
- }
- }
-
- /// Returns `true` if the attribute's path matches the argument.
- /// If it matches, then the attribute is marked as used.
- /// Should only be used by rustc, other tools can use `has_name` instead,
- /// because only rustc is supposed to report the `unused_attributes` lint.
- /// `MetaItem` and `NestedMetaItem` are produced by "lowering" an `Attribute`
- /// and don't have identity, so they only has the `has_name` method,
- /// and you need to mark the original `Attribute` as used when necessary.
- pub fn check_name(&self, name: Symbol) -> bool {
- let matches = self.has_name(name);
- if matches {
- mark_used(self);
+ AttrKind::DocComment(..) => false,
}
- matches
}
/// For a single-segment attribute, returns its name; otherwise, returns `None`.
None
}
}
- AttrKind::DocComment(_) => None,
+ AttrKind::DocComment(..) => None,
}
}
pub fn name_or_empty(&self) -> Symbol {
Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list),
_ => None,
},
- AttrKind::DocComment(_) => None,
+ AttrKind::DocComment(..) => None,
}
}
pub fn is_doc_comment(&self) -> bool {
match self.kind {
AttrKind::Normal(_) => false,
- AttrKind::DocComment(_) => true,
+ AttrKind::DocComment(..) => true,
}
}
pub fn doc_str(&self) -> Option<Symbol> {
match self.kind {
- AttrKind::DocComment(symbol) => Some(symbol),
+ AttrKind::DocComment(.., data) => Some(data),
AttrKind::Normal(ref item) if item.path == sym::doc => {
item.meta(self.span).and_then(|meta| meta.value_str())
}
pub fn get_normal_item(&self) -> &AttrItem {
match self.kind {
AttrKind::Normal(ref item) => item,
- AttrKind::DocComment(_) => panic!("unexpected doc comment"),
+ AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
pub fn unwrap_normal_item(self) -> AttrItem {
match self.kind {
AttrKind::Normal(item) => item,
- AttrKind::DocComment(_) => panic!("unexpected doc comment"),
+ AttrKind::DocComment(..) => panic!("unexpected doc comment"),
}
}
mk_attr(AttrStyle::Outer, item.path, item.kind.mac_args(item.span), item.span)
}
-pub fn mk_doc_comment(style: AttrStyle, comment: Symbol, span: Span) -> Attribute {
- Attribute { kind: AttrKind::DocComment(comment), id: mk_attr_id(), style, span }
+pub fn mk_doc_comment(
+ comment_kind: CommentKind,
+ style: AttrStyle,
+ data: Symbol,
+ span: Span,
+) -> Attribute {
+ Attribute { kind: AttrKind::DocComment(comment_kind, data), id: mk_attr_id(), style, span }
}
pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool {
items.iter().any(|item| item.has_name(name))
}
-pub fn contains_name(attrs: &[Attribute], name: Symbol) -> bool {
- attrs.iter().any(|item| item.check_name(name))
-}
-
-pub fn find_by_name(attrs: &[Attribute], name: Symbol) -> Option<&Attribute> {
- attrs.iter().find(|attr| attr.check_name(name))
-}
-
-pub fn filter_by_name(attrs: &[Attribute], name: Symbol) -> impl Iterator<Item = &Attribute> {
- attrs.iter().filter(move |attr| attr.check_name(name))
-}
-
-pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option<Symbol> {
- attrs.iter().find(|at| at.check_name(name)).and_then(|at| at.value_str())
-}
-
impl MetaItem {
fn token_trees_and_joints(&self) -> Vec<TreeAndJoint> {
let mut idents = vec![];
-use crate::ast::{Item, ItemKind};
-use crate::attr;
-use rustc_span::symbol::sym;
-
pub enum EntryPointType {
None,
MainNamed,
Start,
OtherMain, // Not an entry point, but some other function named main
}
-
-// Beware, this is duplicated in librustc_middle/middle/entry.rs, make sure to keep
-// them in sync.
-pub fn entry_point_type(item: &Item, depth: usize) -> EntryPointType {
- match item.kind {
- ItemKind::Fn(..) => {
- if attr::contains_name(&item.attrs, sym::start) {
- EntryPointType::Start
- } else if attr::contains_name(&item.attrs, sym::main) {
- EntryPointType::MainAttr
- } else if item.ident.name == sym::main {
- if depth == 1 {
- // This is a top-level function so can be 'main'
- EntryPointType::MainNamed
- } else {
- EntryPointType::OtherMain
- }
- } else {
- EntryPointType::None
- }
- }
- _ => EntryPointType::None,
- }
-}
-use crate::{ast, attr, visit};
use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
#[derive(Clone, Copy)]
pub enum AllocatorKind {
output: AllocatorTy::ResultPtr,
},
];
-
-pub fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
- struct Finder {
- name: Symbol,
- spans: Vec<Span>,
- }
- impl<'ast> visit::Visitor<'ast> for Finder {
- fn visit_item(&mut self, item: &'ast ast::Item) {
- if item.ident.name == self.name
- && attr::contains_name(&item.attrs, sym::rustc_std_internal_symbol)
- {
- self.spans.push(item.span);
- }
- visit::walk_item(self, item)
- }
- }
-
- let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc));
- let mut f = Finder { name, spans: Vec::new() };
- visit::walk_crate(&mut f, krate);
- f.spans
-}
//! Definitions shared by macros / syntax extensions and e.g. librustc_middle.
-use crate::ast::Attribute;
-use rustc_span::symbol::sym;
-
pub mod allocator;
-
-pub fn is_proc_macro_attr(attr: &Attribute) -> bool {
- [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
- .iter()
- .any(|kind| attr.check_name(*kind))
-}
pub mod ast;
pub mod attr;
-pub use attr::{with_default_session_globals, with_session_globals, SESSION_GLOBALS};
pub mod crate_disambiguator;
pub mod entry;
pub mod expand;
vis.visit_path(path);
visit_mac_args(args, vis);
}
- AttrKind::DocComment(_) => {}
+ AttrKind::DocComment(..) => {}
}
vis.visit_span(span);
}
use std::borrow::Cow;
use std::{fmt, mem};
+#[derive(Clone, Copy, PartialEq, RustcEncodable, RustcDecodable, Debug, HashStable_Generic)]
+pub enum CommentKind {
+ Line,
+ Block,
+}
+
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
#[derive(HashStable_Generic)]
pub enum BinOpToken {
Interpolated(Lrc<Nonterminal>),
- // Can be expanded into several tokens.
- /// A doc comment.
- DocComment(Symbol),
+ /// A doc comment token.
+ /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
+ /// similarly to symbols in string literal tokens.
+ DocComment(CommentKind, ast::AttrStyle, Symbol),
// Junk. These carry no data because we don't really care about the data
// they *would* carry, and don't really want to allocate a new ident for
-pub use CommentStyle::*;
-
-use crate::ast;
+use crate::ast::AttrStyle;
use rustc_span::source_map::SourceMap;
use rustc_span::{BytePos, CharPos, FileName, Pos, Symbol};
-use log::debug;
-
#[cfg(test)]
mod tests;
pub pos: BytePos,
}
-pub fn is_line_doc_comment(s: &str) -> bool {
- let res = (s.starts_with("///") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'/')
- || s.starts_with("//!");
- debug!("is {:?} a doc comment? {}", s, res);
- res
-}
-
-pub fn is_block_doc_comment(s: &str) -> bool {
- // Prevent `/**/` from being parsed as a doc comment
- let res = ((s.starts_with("/**") && *s.as_bytes().get(3).unwrap_or(&b' ') != b'*')
- || s.starts_with("/*!"))
- && s.len() >= 5;
- debug!("is {:?} a doc comment? {}", s, res);
- res
-}
-
-// FIXME(#64197): Try to privatize this again.
-pub fn is_doc_comment(s: &str) -> bool {
- (s.starts_with("///") && is_line_doc_comment(s))
- || s.starts_with("//!")
- || (s.starts_with("/**") && is_block_doc_comment(s))
- || s.starts_with("/*!")
+/// For a full line comment string returns its doc comment style if it's a doc comment
+/// and returns `None` if it's a regular comment.
+pub fn line_doc_comment_style(line_comment: &str) -> Option<AttrStyle> {
+ let line_comment = line_comment.as_bytes();
+ assert!(line_comment.starts_with(b"//"));
+ match line_comment.get(2) {
+ // `//!` is an inner line doc comment.
+ Some(b'!') => Some(AttrStyle::Inner),
+ Some(b'/') => match line_comment.get(3) {
+ // `////` (more than 3 slashes) is not considered a doc comment.
+ Some(b'/') => None,
+ // Otherwise `///` is an outer line doc comment.
+ _ => Some(AttrStyle::Outer),
+ },
+ _ => None,
+ }
}
-pub fn doc_comment_style(comment: Symbol) -> ast::AttrStyle {
- let comment = &comment.as_str();
- assert!(is_doc_comment(comment));
- if comment.starts_with("//!") || comment.starts_with("/*!") {
- ast::AttrStyle::Inner
- } else {
- ast::AttrStyle::Outer
+/// For a full block comment string returns its doc comment style if it's a doc comment
+/// and returns `None` if it's a regular comment.
+pub fn block_doc_comment_style(block_comment: &str, terminated: bool) -> Option<AttrStyle> {
+ let block_comment = block_comment.as_bytes();
+ assert!(block_comment.starts_with(b"/*"));
+ assert!(!terminated || block_comment.ends_with(b"*/"));
+ match block_comment.get(2) {
+ // `/*!` is an inner block doc comment.
+ Some(b'!') => Some(AttrStyle::Inner),
+ Some(b'*') => match block_comment.get(3) {
+ // `/***` (more than 2 stars) is not considered a doc comment.
+ Some(b'*') => None,
+ // `/**/` is not considered a doc comment.
+ Some(b'/') if block_comment.len() == 4 => None,
+ // Otherwise `/**` is an outer block doc comment.
+ _ => Some(AttrStyle::Outer),
+ },
+ _ => None,
}
}
-pub fn strip_doc_comment_decoration(comment: Symbol) -> String {
- let comment = &comment.as_str();
-
+/// Makes a doc string more presentable to users.
+/// Used by rustdoc and perhaps other tools, but not by rustc.
+pub fn beautify_doc_string(data: Symbol) -> String {
/// remove whitespace-only lines from the start/end of lines
fn vertical_trim(lines: Vec<String>) -> Vec<String> {
let mut i = 0;
}
}
- // one-line comments lose their prefix
- const ONELINERS: &[&str] = &["///!", "///", "//!", "//"];
-
- for prefix in ONELINERS {
- if comment.starts_with(*prefix) {
- return (&comment[prefix.len()..]).to_string();
- }
- }
-
- if comment.starts_with("/*") {
- let lines =
- comment[3..comment.len() - 2].lines().map(|s| s.to_string()).collect::<Vec<String>>();
-
+ let data = data.as_str();
+ if data.contains('\n') {
+ let lines = data.lines().map(|s| s.to_string()).collect::<Vec<String>>();
let lines = vertical_trim(lines);
let lines = horizontal_trim(lines);
-
- return lines.join("\n");
+ lines.join("\n")
+ } else {
+ data.to_string()
}
-
- panic!("not a doc-comment: {}", comment);
}
/// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
if let Some(shebang_len) = rustc_lexer::strip_shebang(text) {
comments.push(Comment {
- style: Isolated,
+ style: CommentStyle::Isolated,
lines: vec![text[..shebang_len].to_string()],
pos: start_bpos,
});
while let Some(next_newline) = &token_text[idx + 1..].find('\n') {
idx = idx + 1 + next_newline;
comments.push(Comment {
- style: BlankLine,
+ style: CommentStyle::BlankLine,
lines: vec![],
pos: start_bpos + BytePos((pos + idx) as u32),
});
}
}
}
- rustc_lexer::TokenKind::BlockComment { terminated: _ } => {
- if !is_block_doc_comment(token_text) {
+ rustc_lexer::TokenKind::BlockComment { terminated } => {
+ if block_doc_comment_style(token_text, terminated).is_none() {
let code_to_the_right = match text[pos + token.len..].chars().next() {
Some('\r' | '\n') => false,
_ => true,
};
let style = match (code_to_the_left, code_to_the_right) {
- (_, true) => Mixed,
- (false, false) => Isolated,
- (true, false) => Trailing,
+ (_, true) => CommentStyle::Mixed,
+ (false, false) => CommentStyle::Isolated,
+ (true, false) => CommentStyle::Trailing,
};
// Count the number of chars since the start of the line by rescanning.
}
}
rustc_lexer::TokenKind::LineComment => {
- if !is_doc_comment(token_text) {
+ if line_doc_comment_style(token_text).is_none() {
comments.push(Comment {
- style: if code_to_the_left { Trailing } else { Isolated },
+ style: if code_to_the_left {
+ CommentStyle::Trailing
+ } else {
+ CommentStyle::Isolated
+ },
lines: vec![token_text.to_string()],
pos: start_bpos + BytePos(pos as u32),
})
use super::*;
-use crate::with_default_session_globals;
+use rustc_span::with_default_session_globals;
+
+#[test]
+fn line_doc_comments() {
+ assert!(line_doc_comment_style("///").is_some());
+ assert!(line_doc_comment_style("/// blah").is_some());
+ assert!(line_doc_comment_style("////").is_none());
+}
#[test]
fn test_block_doc_comment_1() {
with_default_session_globals(|| {
- let comment = "/**\n * Test \n ** Test\n * Test\n*/";
- let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+ let comment = "\n * Test \n ** Test\n * Test\n";
+ let stripped = beautify_doc_string(Symbol::intern(comment));
assert_eq!(stripped, " Test \n* Test\n Test");
})
}
#[test]
fn test_block_doc_comment_2() {
with_default_session_globals(|| {
- let comment = "/**\n * Test\n * Test\n*/";
- let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+ let comment = "\n * Test\n * Test\n";
+ let stripped = beautify_doc_string(Symbol::intern(comment));
assert_eq!(stripped, " Test\n Test");
})
}
#[test]
fn test_block_doc_comment_3() {
with_default_session_globals(|| {
- let comment = "/**\n let a: *i32;\n *a = 5;\n*/";
- let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
+ let comment = "\n let a: *i32;\n *a = 5;\n";
+ let stripped = beautify_doc_string(Symbol::intern(comment));
assert_eq!(stripped, " let a: *i32;\n *a = 5;");
})
}
-#[test]
-fn test_block_doc_comment_4() {
- with_default_session_globals(|| {
- let comment = "/*******************\n test\n *********************/";
- let stripped = strip_doc_comment_decoration(Symbol::intern(comment));
- assert_eq!(stripped, " test");
- })
-}
-
#[test]
fn test_line_doc_comment() {
with_default_session_globals(|| {
- let stripped = strip_doc_comment_decoration(Symbol::intern("/// test"));
- assert_eq!(stripped, " test");
- let stripped = strip_doc_comment_decoration(Symbol::intern("///! test"));
- assert_eq!(stripped, " test");
- let stripped = strip_doc_comment_decoration(Symbol::intern("// test"));
+ let stripped = beautify_doc_string(Symbol::intern(" test"));
assert_eq!(stripped, " test");
- let stripped = strip_doc_comment_decoration(Symbol::intern("// test"));
- assert_eq!(stripped, " test");
- let stripped = strip_doc_comment_decoration(Symbol::intern("///test"));
- assert_eq!(stripped, "test");
- let stripped = strip_doc_comment_decoration(Symbol::intern("///!test"));
- assert_eq!(stripped, "test");
- let stripped = strip_doc_comment_decoration(Symbol::intern("//test"));
+ let stripped = beautify_doc_string(Symbol::intern("! test"));
+ assert_eq!(stripped, "! test");
+ let stripped = beautify_doc_string(Symbol::intern("test"));
assert_eq!(stripped, "test");
+ let stripped = beautify_doc_string(Symbol::intern("!test"));
+ assert_eq!(stripped, "!test");
})
}
#[test]
fn test_find_best_match_for_name() {
- use crate::with_default_session_globals;
+ use rustc_span::with_default_session_globals;
with_default_session_globals(|| {
let input = vec![Symbol::intern("aaab"), Symbol::intern("aaabc")];
assert_eq!(
pub fn walk_attribute<'a, V: Visitor<'a>>(visitor: &mut V, attr: &'a Attribute) {
match attr.kind {
AttrKind::Normal(ref item) => walk_mac_args(visitor, &item.args),
- AttrKind::DocComment(_) => {}
+ AttrKind::DocComment(..) => {}
}
}
.collect();
// Stop if there were any errors when lowering the register classes
- if operands.len() != asm.operands.len() {
+ if operands.len() != asm.operands.len() || sess.asm_arch.is_none() {
return hir::ExprKind::Err;
}
use crate::Arena;
use rustc_ast::ast::*;
-use rustc_ast::attr;
use rustc_ast::node_id::NodeMap;
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, AssocCtxt, Visitor};
let attrs = self.lower_attrs(&i.attrs);
if let ItemKind::MacroDef(MacroDef { ref body, macro_rules }) = i.kind {
- if !macro_rules || attr::contains_name(&i.attrs, sym::macro_export) {
+ if !macro_rules || self.sess.contains_name(&i.attrs, sym::macro_export) {
let hir_id = self.lower_node_id(i.id);
let body = P(self.lower_mac_args(body));
self.exported_macros.push(hir::MacroDef {
use rustc_ast::ast;
use rustc_ast::ast::*;
-use rustc_ast::attr;
use rustc_ast::node_id::NodeMap;
use rustc_ast::token::{self, DelimToken, Nonterminal, Token};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
.resolver
.trait_map()
.iter()
- .map(|(&k, v)| (self.node_id_to_hir_id[k].unwrap(), v.clone()))
+ .filter_map(|(&k, v)| {
+ self.node_id_to_hir_id.get(k).and_then(|id| id.as_ref()).map(|id| (*id, v.clone()))
+ })
.collect();
let mut def_id_to_hir_id = IndexVec::default();
path: item.path.clone(),
args: self.lower_mac_args(&item.args),
}),
- AttrKind::DocComment(comment) => AttrKind::DocComment(comment),
+ AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data),
};
Attribute { kind, id: attr.id, style: attr.style, span: attr.span }
synthetic: param
.attrs
.iter()
- .filter(|attr| attr.check_name(sym::rustc_synthetic))
+ .filter(|attr| self.sess.check_name(attr, sym::rustc_synthetic))
.map(|_| hir::SyntheticTyParamKind::ImplTrait)
.next(),
};
hir_id: self.lower_node_id(param.id),
name,
span: param.ident.span,
- pure_wrt_drop: attr::contains_name(¶m.attrs, sym::may_dangle),
+ pure_wrt_drop: self.sess.contains_name(¶m.attrs, sym::may_dangle),
attrs: self.lower_attrs(¶m.attrs),
bounds: self.arena.alloc_from_iter(bounds),
kind,
use itertools::{Either, Itertools};
use rustc_ast::ast::*;
-use rustc_ast::attr;
-use rustc_ast::expand::is_proc_macro_attr;
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
use rustc_ast::walk_list;
span,
&format!(
"reorder the parameters: lifetimes, then types{}",
- if sess.features_untracked().const_generics { ", then consts" } else { "" },
+ if sess.features_untracked().const_generics
+ || sess.features_untracked().min_const_generics
+ {
+ ", then consts"
+ } else {
+ ""
+ },
),
ordered_params.clone(),
Applicability::MachineApplicable,
}
fn visit_item(&mut self, item: &'a Item) {
- if item.attrs.iter().any(|attr| is_proc_macro_attr(attr)) {
+ if item.attrs.iter().any(|attr| self.session.is_proc_macro_attr(attr)) {
self.has_proc_macro_decls = true;
}
- if attr::contains_name(&item.attrs, sym::no_mangle) {
+ if self.session.contains_name(&item.attrs, sym::no_mangle) {
self.check_nomangle_item_asciionly(item.ident, item.span);
}
}
ItemKind::Mod(Mod { inline, .. }) => {
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
- if !inline && !attr::contains_name(&item.attrs, sym::path) {
+ if !inline && !self.session.contains_name(&item.attrs, sym::path) {
self.check_mod_file_item_asciionly(item.ident);
}
}
use rustc_ast::ast::{self, AssocTyConstraint, AssocTyConstraintKind, NodeId};
use rustc_ast::ast::{GenericParam, GenericParamKind, PatKind, RangeEnd, VariantData};
-use rustc_ast::attr;
use rustc_ast::visit::{self, AssocCtxt, FnCtxt, FnKind, Visitor};
-use rustc_errors::{struct_span_err, Handler};
+use rustc_errors::struct_span_err;
use rustc_feature::{AttributeGate, BUILTIN_ATTRIBUTE_MAP};
-use rustc_feature::{Features, GateIssue, UnstableFeatures};
-use rustc_session::parse::{feature_err, feature_err_issue, ParseSess};
+use rustc_feature::{Features, GateIssue};
+use rustc_session::parse::{feature_err, feature_err_issue};
+use rustc_session::Session;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
use tracing::debug;
macro_rules! gate_feature_fn {
- ($cx: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
- let (cx, has_feature, span, name, explain) = (&*$cx, $has_feature, $span, $name, $explain);
- let has_feature: bool = has_feature(&$cx.features);
+ ($visitor: expr, $has_feature: expr, $span: expr, $name: expr, $explain: expr) => {{
+ let (visitor, has_feature, span, name, explain) =
+ (&*$visitor, $has_feature, $span, $name, $explain);
+ let has_feature: bool = has_feature(visitor.features);
debug!("gate_feature(feature = {:?}, span = {:?}); has? {}", name, span, has_feature);
if !has_feature && !span.allows_unstable($name) {
- feature_err_issue(cx.parse_sess, name, span, GateIssue::Language, explain).emit();
+ feature_err_issue(&visitor.sess.parse_sess, name, span, GateIssue::Language, explain)
+ .emit();
}
}};
}
macro_rules! gate_feature_post {
- ($cx: expr, $feature: ident, $span: expr, $explain: expr) => {
- gate_feature_fn!($cx, |x: &Features| x.$feature, $span, sym::$feature, $explain)
+ ($visitor: expr, $feature: ident, $span: expr, $explain: expr) => {
+ gate_feature_fn!($visitor, |x: &Features| x.$feature, $span, sym::$feature, $explain)
};
}
-pub fn check_attribute(attr: &ast::Attribute, parse_sess: &ParseSess, features: &Features) {
- PostExpansionVisitor { parse_sess, features }.visit_attribute(attr)
+pub fn check_attribute(attr: &ast::Attribute, sess: &Session, features: &Features) {
+ PostExpansionVisitor { sess, features }.visit_attribute(attr)
}
struct PostExpansionVisitor<'a> {
- parse_sess: &'a ParseSess,
+ sess: &'a Session,
+
+ // `sess` contains a `Features`, but this might not be that one.
features: &'a Features,
}
);
}
abi => self
+ .sess
.parse_sess
.span_diagnostic
.delay_span_bug(span, &format!("unrecognized ABI not caught in lowering: {}", abi)),
if !discriminant_spans.is_empty() && has_fields {
let mut err = feature_err(
- self.parse_sess,
+ &self.sess.parse_sess,
sym::arbitrary_enum_discriminant,
discriminant_spans.clone(),
"custom discriminant values are not allowed in enums with tuple or struct variants",
gate_feature_fn!(self, has_feature, attr.span, name, descr);
}
// Check unstable flavors of the `#[doc]` attribute.
- if attr.check_name(sym::doc) {
+ if self.sess.check_name(attr, sym::doc) {
for nested_meta in attr.meta_item_list().unwrap_or_default() {
macro_rules! gate_doc { ($($name:ident => $feature:ident)*) => {
$(if nested_meta.has_name(sym::$name) {
gate_feature_post!(
&self,
non_ascii_idents,
- self.parse_sess.source_map().guess_head_span(sp),
+ self.sess.parse_sess.source_map().guess_head_span(sp),
"non-ascii idents are not fully supported"
);
}
}
ast::ItemKind::Fn(..) => {
- if attr::contains_name(&i.attrs[..], sym::plugin_registrar) {
+ if self.sess.contains_name(&i.attrs[..], sym::plugin_registrar) {
gate_feature_post!(
&self,
plugin_registrar,
"compiler plugins are experimental and possibly buggy"
);
}
- if attr::contains_name(&i.attrs[..], sym::start) {
+ if self.sess.contains_name(&i.attrs[..], sym::start) {
gate_feature_post!(
&self,
start,
over time"
);
}
- if attr::contains_name(&i.attrs[..], sym::main) {
+ if self.sess.contains_name(&i.attrs[..], sym::main) {
gate_feature_post!(
&self,
main,
}
ast::ItemKind::Struct(..) => {
- for attr in attr::filter_by_name(&i.attrs[..], sym::repr) {
+ for attr in self.sess.filter_by_name(&i.attrs[..], sym::repr) {
for item in attr.meta_item_list().unwrap_or_else(Vec::new) {
if item.has_name(sym::simd) {
gate_feature_post!(
fn visit_foreign_item(&mut self, i: &'a ast::ForeignItem) {
match i.kind {
ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
- let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
+ let link_name = self.sess.first_attr_value_str_by_name(&i.attrs, sym::link_name);
let links_to_llvm = match link_name {
Some(val) => val.as_str().starts_with("llvm."),
_ => false,
ast::ExprKind::Type(..) => {
// To avoid noise about type ascription in common syntax errors, only emit if it
// is the *only* error.
- if self.parse_sess.span_diagnostic.err_count() == 0 {
+ if self.sess.parse_sess.span_diagnostic.err_count() == 0 {
gate_feature_post!(
&self,
type_ascription,
fn visit_generic_param(&mut self, param: &'a GenericParam) {
if let GenericParamKind::Const { .. } = param.kind {
- gate_feature_post!(
+ gate_feature_fn!(
&self,
- const_generics,
+ |x: &Features| x.const_generics || x.min_const_generics,
param.ident.span,
+ sym::min_const_generics,
"const generics are unstable"
- )
+ );
}
visit::walk_generic_param(self, param)
}
}
}
-pub fn check_crate(
- krate: &ast::Crate,
- parse_sess: &ParseSess,
- features: &Features,
- unstable: UnstableFeatures,
-) {
- maybe_stage_features(&parse_sess.span_diagnostic, krate, unstable);
- let mut visitor = PostExpansionVisitor { parse_sess, features };
+pub fn check_crate(krate: &ast::Crate, sess: &Session) {
+ maybe_stage_features(sess, krate);
+ let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() };
- let spans = parse_sess.gated_spans.spans.borrow();
+ let spans = sess.parse_sess.gated_spans.spans.borrow();
macro_rules! gate_all {
($gate:ident, $msg:literal) => {
for span in spans.get(&sym::$gate).unwrap_or(&vec![]) {
gate_all!(box_syntax, "box expression syntax is experimental; you can call `Box::new` instead");
// To avoid noise about type ascription in common syntax errors,
// only emit if it is the *only* error. (Also check it last.)
- if parse_sess.span_diagnostic.err_count() == 0 {
+ if sess.parse_sess.span_diagnostic.err_count() == 0 {
gate_all!(type_ascription, "type ascription is experimental");
}
visit::walk_crate(&mut visitor, krate);
}
-fn maybe_stage_features(span_handler: &Handler, krate: &ast::Crate, unstable: UnstableFeatures) {
- if !unstable.is_nightly_build() {
- for attr in krate.attrs.iter().filter(|attr| attr.check_name(sym::feature)) {
+fn maybe_stage_features(sess: &Session, krate: &ast::Crate) {
+ if !sess.opts.unstable_features.is_nightly_build() {
+ for attr in krate.attrs.iter().filter(|attr| sess.check_name(attr, sym::feature)) {
struct_span_err!(
- span_handler,
+ sess.parse_sess.span_diagnostic,
attr.span,
E0554,
"`#![feature]` may not be used on the {} release channel",
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_ast::attr;
use rustc_ast::ptr::P;
-use rustc_ast::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind};
+use rustc_ast::token::{self, BinOpToken, CommentKind, DelimToken, Nonterminal, Token, TokenKind};
use rustc_ast::tokenstream::{TokenStream, TokenTree};
+use rustc_ast::util::classify;
+use rustc_ast::util::comments::{gather_comments, Comment, CommentStyle};
use rustc_ast::util::parser::{self, AssocOp, Fixity};
-use rustc_ast::util::{classify, comments};
use rustc_span::edition::Edition;
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
pub struct Comments<'a> {
sm: &'a SourceMap,
- comments: Vec<comments::Comment>,
+ comments: Vec<Comment>,
current: usize,
}
impl<'a> Comments<'a> {
pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
- let comments = comments::gather_comments(sm, filename, input);
+ let comments = gather_comments(sm, filename, input);
Comments { sm, comments, current: 0 }
}
- pub fn next(&self) -> Option<comments::Comment> {
+ pub fn next(&self) -> Option<Comment> {
self.comments.get(self.current).cloned()
}
&mut self,
span: rustc_span::Span,
next_pos: Option<BytePos>,
- ) -> Option<comments::Comment> {
+ ) -> Option<Comment> {
if let Some(cmnt) = self.next() {
- if cmnt.style != comments::Trailing {
+ if cmnt.style != CommentStyle::Trailing {
return None;
}
let span_line = self.sm.lookup_char_pos(span.hi());
// and also addresses some specific regressions described in #63896 and #73345.
fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool {
if let TokenTree::Token(token) = prev {
- if let token::DocComment(s) = token.kind {
- return !s.as_str().starts_with("//");
+ if let token::DocComment(comment_kind, ..) = token.kind {
+ return comment_kind != CommentKind::Line;
}
}
match tt {
}
}
+fn doc_comment_to_string(
+ comment_kind: CommentKind,
+ attr_style: ast::AttrStyle,
+ data: Symbol,
+) -> String {
+ match (comment_kind, attr_style) {
+ (CommentKind::Line, ast::AttrStyle::Outer) => format!("///{}", data),
+ (CommentKind::Line, ast::AttrStyle::Inner) => format!("//!{}", data),
+ (CommentKind::Block, ast::AttrStyle::Outer) => format!("/**{}*/", data),
+ (CommentKind::Block, ast::AttrStyle::Inner) => format!("/*!{}*/", data),
+ }
+}
+
pub fn literal_to_string(lit: token::Lit) -> String {
let token::Lit { kind, symbol, suffix } = lit;
let mut out = match kind {
token::Lifetime(s) => s.to_string(),
/* Other */
- token::DocComment(s) => s.to_string(),
+ token::DocComment(comment_kind, attr_style, data) => {
+ doc_comment_to_string(comment_kind, attr_style, data)
+ }
token::Eof => "<eof>".to_string(),
token::Whitespace => " ".to_string(),
token::Comment => "/* */".to_string(),
}
}
- fn print_comment(&mut self, cmnt: &comments::Comment) {
+ fn print_comment(&mut self, cmnt: &Comment) {
match cmnt.style {
- comments::Mixed => {
+ CommentStyle::Mixed => {
if !self.is_beginning_of_line() {
self.zerobreak();
}
}
self.zerobreak()
}
- comments::Isolated => {
+ CommentStyle::Isolated => {
self.hardbreak_if_not_bol();
for line in &cmnt.lines {
// Don't print empty lines because they will end up as trailing
self.hardbreak();
}
}
- comments::Trailing => {
+ CommentStyle::Trailing => {
if !self.is_beginning_of_line() {
self.word(" ");
}
self.end();
}
}
- comments::BlankLine => {
+ CommentStyle::BlankLine => {
// We need to do at least one, possibly two hardbreaks.
let twice = match self.last_token() {
pp::Token::String(s) => ";" == s,
}
}
- fn next_comment(&mut self) -> Option<comments::Comment> {
+ fn next_comment(&mut self) -> Option<Comment> {
self.comments().as_mut().and_then(|c| c.next())
}
self.print_attr_item(&item, attr.span);
self.word("]");
}
- ast::AttrKind::DocComment(comment) => {
- self.word(comment.to_string());
+ ast::AttrKind::DocComment(comment_kind, data) => {
+ self.word(doc_comment_to_string(comment_kind, attr.style, data));
self.hardbreak()
}
}
use super::*;
use rustc_ast::ast;
-use rustc_ast::with_default_session_globals;
use rustc_span::source_map::respan;
use rustc_span::symbol::Ident;
+use rustc_span::with_default_session_globals;
fn fun_to_string(
decl: &ast::FnDecl,
//! Parsing and validation of builtin attributes
-use super::{find_by_name, mark_used};
-
use rustc_ast::ast::{self, Attribute, Lit, LitKind, MetaItem, MetaItemKind, NestedMetaItem};
use rustc_ast_pretty::pprust;
-use rustc_errors::{struct_span_err, Applicability, Handler};
+use rustc_errors::{struct_span_err, Applicability};
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
use rustc_macros::HashStable_Generic;
use rustc_session::parse::{feature_err, ParseSess};
+use rustc_session::Session;
use rustc_span::hygiene::Transparency;
use rustc_span::{symbol::sym, symbol::Symbol, Span};
use std::num::NonZeroU32;
}
/// Determine what `#[unwind]` attribute is present in `attrs`, if any.
-pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option<UnwindAttr> {
+pub fn find_unwind_attr(sess: &Session, attrs: &[Attribute]) -> Option<UnwindAttr> {
attrs.iter().fold(None, |ia, attr| {
- if attr.check_name(sym::unwind) {
+ if sess.check_name(attr, sym::unwind) {
if let Some(meta) = attr.meta() {
if let MetaItemKind::List(items) = meta.kind {
if items.len() == 1 {
}
}
- if let Some(d) = diagnostic {
- struct_span_err!(d, attr.span, E0633, "malformed `unwind` attribute input")
- .span_label(attr.span, "invalid argument")
- .span_suggestions(
- attr.span,
- "the allowed arguments are `allowed` and `aborts`",
- (vec!["allowed", "aborts"])
- .into_iter()
- .map(|s| format!("#[unwind({})]", s)),
- Applicability::MachineApplicable,
- )
- .emit();
- };
+ struct_span_err!(
+ sess.diagnostic(),
+ attr.span,
+ E0633,
+ "malformed `unwind` attribute input"
+ )
+ .span_label(attr.span, "invalid argument")
+ .span_suggestions(
+ attr.span,
+ "the allowed arguments are `allowed` and `aborts`",
+ (vec!["allowed", "aborts"])
+ .into_iter()
+ .map(|s| format!("#[unwind({})]", s)),
+ Applicability::MachineApplicable,
+ )
+ .emit();
}
}
}
}
}
-/// Checks if `attrs` contains an attribute like `#![feature(feature_name)]`.
-/// This will not perform any "sanity checks" on the form of the attributes.
-pub fn contains_feature_attr(attrs: &[Attribute], feature_name: Symbol) -> bool {
- attrs.iter().any(|item| {
- item.check_name(sym::feature)
- && item
- .meta_item_list()
- .map(|list| list.iter().any(|mi| mi.is_word() && mi.has_name(feature_name)))
- .unwrap_or(false)
- })
-}
-
/// Collects stability info from all stability attributes in `attrs`.
/// Returns `None` if no stability attributes are found.
pub fn find_stability(
- sess: &ParseSess,
+ sess: &Session,
attrs: &[Attribute],
item_sp: Span,
) -> (Option<Stability>, Option<ConstStability>) {
}
fn find_stability_generic<'a, I>(
- sess: &ParseSess,
+ sess: &Session,
attrs_iter: I,
item_sp: Span,
) -> (Option<Stability>, Option<ConstStability>)
let mut const_stab: Option<ConstStability> = None;
let mut promotable = false;
let mut allow_const_fn_ptr = false;
- let diagnostic = &sess.span_diagnostic;
+ let diagnostic = &sess.parse_sess.span_diagnostic;
'outer: for attr in attrs_iter {
if ![
continue; // not a stability level
}
- mark_used(attr);
+ sess.mark_attr_used(attr);
let meta = attr.meta();
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
if item.is_some() {
handle_errors(
- sess,
+ &sess.parse_sess,
meta.span,
AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
);
match meta_name {
sym::rustc_const_unstable | sym::unstable => {
if meta_name == sym::unstable && stab.is_some() {
- handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+ handle_errors(
+ &sess.parse_sess,
+ attr.span,
+ AttrError::MultipleStabilityLevels,
+ );
break;
} else if meta_name == sym::rustc_const_unstable && const_stab.is_some() {
- handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+ handle_errors(
+ &sess.parse_sess,
+ attr.span,
+ AttrError::MultipleStabilityLevels,
+ );
break;
}
sym::soft => {
if !mi.is_word() {
let msg = "`soft` should not have any arguments";
- sess.span_diagnostic.span_err(mi.span, msg);
+ sess.parse_sess.span_diagnostic.span_err(mi.span, msg);
}
is_soft = true;
}
_ => {
handle_errors(
- sess,
+ &sess.parse_sess,
meta.span(),
AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path),
}
} else {
handle_errors(
- sess,
+ &sess.parse_sess,
meta.span(),
AttrError::UnsupportedLiteral("unsupported literal", false),
);
}
}
(None, _, _) => {
- handle_errors(sess, attr.span, AttrError::MissingFeature);
+ handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
continue;
}
_ => {
}
sym::rustc_const_stable | sym::stable => {
if meta_name == sym::stable && stab.is_some() {
- handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+ handle_errors(
+ &sess.parse_sess,
+ attr.span,
+ AttrError::MultipleStabilityLevels,
+ );
break;
} else if meta_name == sym::rustc_const_stable && const_stab.is_some() {
- handle_errors(sess, attr.span, AttrError::MultipleStabilityLevels);
+ handle_errors(
+ &sess.parse_sess,
+ attr.span,
+ AttrError::MultipleStabilityLevels,
+ );
break;
}
}
_ => {
handle_errors(
- sess,
+ &sess.parse_sess,
meta.span(),
AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path),
},
NestedMetaItem::Literal(lit) => {
handle_errors(
- sess,
+ &sess.parse_sess,
lit.span,
AttrError::UnsupportedLiteral("unsupported literal", false),
);
}
}
(None, _) => {
- handle_errors(sess, attr.span, AttrError::MissingFeature);
+ handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature);
continue;
}
_ => {
- handle_errors(sess, attr.span, AttrError::MissingSince);
+ handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
continue;
}
}
(stab, const_stab)
}
-pub fn find_crate_name(attrs: &[Attribute]) -> Option<Symbol> {
- super::first_attr_value_str_by_name(attrs, sym::crate_name)
+pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option<Symbol> {
+ sess.first_attr_value_str_by_name(attrs, sym::crate_name)
}
/// Tests if a cfg-pattern matches the cfg set
}
/// Finds the deprecation attribute. `None` if none exists.
-pub fn find_deprecation(
- sess: &ParseSess,
- attrs: &[Attribute],
- item_sp: Span,
-) -> Option<Deprecation> {
+pub fn find_deprecation(sess: &Session, attrs: &[Attribute], item_sp: Span) -> Option<Deprecation> {
find_deprecation_generic(sess, attrs.iter(), item_sp)
}
fn find_deprecation_generic<'a, I>(
- sess: &ParseSess,
+ sess: &Session,
attrs_iter: I,
item_sp: Span,
) -> Option<Deprecation>
I: Iterator<Item = &'a Attribute>,
{
let mut depr: Option<Deprecation> = None;
- let diagnostic = &sess.span_diagnostic;
+ let diagnostic = &sess.parse_sess.span_diagnostic;
'outer: for attr in attrs_iter {
- if !(attr.check_name(sym::deprecated) || attr.check_name(sym::rustc_deprecated)) {
+ if !(sess.check_name(attr, sym::deprecated) || sess.check_name(attr, sym::rustc_deprecated))
+ {
continue;
}
let get = |meta: &MetaItem, item: &mut Option<Symbol>| {
if item.is_some() {
handle_errors(
- sess,
+ &sess.parse_sess,
meta.span,
AttrError::MultipleItem(pprust::path_to_string(&meta.path)),
);
} else {
if let Some(lit) = meta.name_value_literal() {
handle_errors(
- sess,
+ &sess.parse_sess,
lit.span,
AttrError::UnsupportedLiteral(
"literal in `deprecated` \
continue 'outer;
}
}
- sym::note if attr.check_name(sym::deprecated) => {
+ sym::note if sess.check_name(attr, sym::deprecated) => {
if !get(mi, &mut note) {
continue 'outer;
}
}
- sym::reason if attr.check_name(sym::rustc_deprecated) => {
+ sym::reason if sess.check_name(attr, sym::rustc_deprecated) => {
if !get(mi, &mut note) {
continue 'outer;
}
}
- sym::suggestion if attr.check_name(sym::rustc_deprecated) => {
+ sym::suggestion if sess.check_name(attr, sym::rustc_deprecated) => {
if !get(mi, &mut suggestion) {
continue 'outer;
}
}
_ => {
handle_errors(
- sess,
+ &sess.parse_sess,
meta.span(),
AttrError::UnknownMetaItem(
pprust::path_to_string(&mi.path),
- if attr.check_name(sym::deprecated) {
+ if sess.check_name(attr, sym::deprecated) {
&["since", "note"]
} else {
&["since", "reason", "suggestion"]
},
NestedMetaItem::Literal(lit) => {
handle_errors(
- sess,
+ &sess.parse_sess,
lit.span,
AttrError::UnsupportedLiteral(
"item in `deprecated` must be a key/value pair",
}
}
- if suggestion.is_some() && attr.check_name(sym::deprecated) {
+ if suggestion.is_some() && sess.check_name(attr, sym::deprecated) {
unreachable!("only allowed on rustc_deprecated")
}
- if attr.check_name(sym::rustc_deprecated) {
+ if sess.check_name(attr, sym::rustc_deprecated) {
if since.is_none() {
- handle_errors(sess, attr.span, AttrError::MissingSince);
+ handle_errors(&sess.parse_sess, attr.span, AttrError::MissingSince);
continue;
}
}
}
- mark_used(&attr);
+ sess.mark_attr_used(&attr);
- let is_since_rustc_version = attr.check_name(sym::rustc_deprecated);
+ let is_since_rustc_version = sess.check_name(attr, sym::rustc_deprecated);
depr = Some(Deprecation { since, note, suggestion, is_since_rustc_version });
}
/// the same discriminant size that the corresponding C enum would or C
/// structure layout, `packed` to remove padding, and `transparent` to elegate representation
/// concerns to the only non-ZST field.
-pub fn find_repr_attrs(sess: &ParseSess, attr: &Attribute) -> Vec<ReprAttr> {
+pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec<ReprAttr> {
use ReprAttr::*;
let mut acc = Vec::new();
- let diagnostic = &sess.span_diagnostic;
+ let diagnostic = &sess.parse_sess.span_diagnostic;
if attr.has_name(sym::repr) {
if let Some(items) = attr.meta_item_list() {
- mark_used(attr);
+ sess.mark_attr_used(attr);
for item in items {
if !item.is_meta_item() {
handle_errors(
- sess,
+ &sess.parse_sess,
item.span(),
AttrError::UnsupportedLiteral(
"meta item in `repr` must be an identifier",
}
pub fn find_transparency(
+ sess: &Session,
attrs: &[Attribute],
macro_rules: bool,
) -> (Transparency, Option<TransparencyError>) {
let mut transparency = None;
let mut error = None;
for attr in attrs {
- if attr.check_name(sym::rustc_macro_transparency) {
+ if sess.check_name(attr, sym::rustc_macro_transparency) {
if let Some((_, old_span)) = transparency {
error = Some(TransparencyError::MultipleTransparencyAttrs(old_span, attr.span));
break;
}
pub fn allow_internal_unstable<'a>(
+ sess: &'a Session,
attrs: &[Attribute],
- diag: &'a rustc_errors::Handler,
) -> Option<impl Iterator<Item = Symbol> + 'a> {
- let attr = find_by_name(attrs, sym::allow_internal_unstable)?;
+ let attr = sess.find_by_name(attrs, sym::allow_internal_unstable)?;
let list = attr.meta_item_list().or_else(|| {
- diag.span_err(attr.span, "allow_internal_unstable expects list of feature names");
+ sess.diagnostic()
+ .span_err(attr.span, "allow_internal_unstable expects list of feature names");
None
})?;
Some(list.into_iter().filter_map(move |it| {
let name = it.ident().map(|ident| ident.name);
if name.is_none() {
- diag.span_err(it.span(), "`allow_internal_unstable` expects feature names");
+ sess.diagnostic()
+ .span_err(it.span(), "`allow_internal_unstable` expects feature names");
}
name
}))
match parse_cfg(cx, sp, tts) {
Ok(cfg) => {
- let matches_cfg = attr::cfg_matches(&cfg, cx.parse_sess, cx.ecfg.features);
+ let matches_cfg = attr::cfg_matches(&cfg, &cx.sess.parse_sess, cx.ecfg.features);
MacEager::expr(cx.expr_bool(sp, matches_cfg))
}
Err(mut err) => {
) -> ExpandResult<Vec<Annotatable>, Annotatable> {
let template = AttributeTemplate { list: Some("path"), ..Default::default() };
let attr = &ecx.attribute(meta_item.clone());
- validate_attr::check_builtin_attribute(ecx.parse_sess, attr, sym::cfg_accessible, template);
+ validate_attr::check_builtin_attribute(
+ &ecx.sess.parse_sess,
+ attr,
+ sym::cfg_accessible,
+ template,
+ );
let path = match validate_input(ecx, meta_item) {
Some(path) => path,
},
StaticEnum(..) => {
struct_span_err!(
- cx.parse_sess.span_diagnostic,
+ &cx.sess.parse_sess.span_diagnostic,
trait_span,
E0665,
"`Default` cannot be derived for enums, only structs"
match *item {
Annotatable::Item(ref item) => {
let is_packed = item.attrs.iter().any(|attr| {
- for r in attr::find_repr_attrs(&cx.parse_sess, attr) {
+ for r in attr::find_repr_attrs(&cx.sess, attr) {
if let attr::ReprPacked(_) = r {
return true;
}
let attr = cx.attribute(cx.meta_word(self.span, sym::automatically_derived));
// Just mark it now since we know that it'll end up used downstream
- attr::mark_used(&attr);
+ cx.sess.mark_attr_used(&attr);
let opt_trait_ref = Some(trait_ref);
let unused_qual = {
let word = rustc_ast::attr::mk_nested_word_item(Ident::new(
let sp = cx.with_def_site_ctxt(sp);
let value = env::var(&var.as_str()).ok().as_deref().map(Symbol::intern);
- cx.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value));
+ cx.sess.parse_sess.env_depinfo.borrow_mut().insert((Symbol::intern(&var), value));
let e = match value {
None => {
let lt = cx.lifetime(sp, Ident::new(kw::StaticLifetime, sp));
let sp = cx.with_def_site_ctxt(sp);
let value = env::var(&*var.as_str()).ok().as_deref().map(Symbol::intern);
- cx.parse_sess.env_depinfo.borrow_mut().insert((var, value));
+ cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
let e = match value {
None => {
cx.span_err(sp, &msg.as_str());
check_builtin_macro_attribute(ecx, meta_item, sym::global_allocator);
let not_static = |item: Annotatable| {
- ecx.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
+ ecx.sess.parse_sess.span_diagnostic.span_err(item.span(), "allocators must be statics");
vec![item]
};
let item = match item {
// If we already have a string with instructions,
// ending up in Asm state again is an error.
return Err(struct_span_err!(
- cx.parse_sess.span_diagnostic,
+ cx.sess.parse_sess.span_diagnostic,
sp,
E0660,
"malformed inline assembly"
Some('+') => Some(Symbol::intern(&format!("={}", ch.as_str()))),
_ => {
struct_span_err!(
- cx.parse_sess.span_diagnostic,
+ cx.sess.parse_sess.span_diagnostic,
span,
E0661,
"output operand constraint lacks '=' or '+'"
if constraint.as_str().starts_with('=') {
struct_span_err!(
- cx.parse_sess.span_diagnostic,
+ cx.sess.parse_sess.span_diagnostic,
p.prev_token.span,
E0662,
"input operand constraint contains '='"
.emit();
} else if constraint.as_str().starts_with('+') {
struct_span_err!(
- cx.parse_sess.span_diagnostic,
+ cx.sess.parse_sess.span_diagnostic,
p.prev_token.span,
E0663,
"input operand constraint contains '+'"
cx.span_warn(p.prev_token.span, "expected a clobber, found an option");
} else if s.as_str().starts_with('{') || s.as_str().ends_with('}') {
struct_span_err!(
- cx.parse_sess.span_diagnostic,
+ cx.sess.parse_sess.span_diagnostic,
p.prev_token.span,
E0664,
"clobber should not be surrounded by braces"
use rustc_ast::ast::{self, NodeId};
use rustc_ast::attr;
-use rustc_ast::expand::is_proc_macro_attr;
use rustc_ast::ptr::P;
use rustc_ast::visit::{self, Visitor};
use rustc_ast_pretty::pprust;
use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
-use rustc_session::parse::ParseSess;
+use rustc_session::Session;
use rustc_span::hygiene::AstPass;
use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
}
struct CollectProcMacros<'a> {
+ sess: &'a Session,
macros: Vec<ProcMacro>,
in_root: bool,
handler: &'a rustc_errors::Handler,
}
pub fn inject(
- sess: &ParseSess,
+ sess: &Session,
resolver: &mut dyn ResolverExpand,
mut krate: ast::Crate,
is_proc_macro_crate: bool,
let mut cx = ExtCtxt::new(sess, ecfg, resolver, None);
let mut collect = CollectProcMacros {
+ sess,
macros: Vec::new(),
in_root: true,
handler,
impl<'a> Visitor<'a> for CollectProcMacros<'a> {
fn visit_item(&mut self, item: &'a ast::Item) {
if let ast::ItemKind::MacroDef(..) = item.kind {
- if self.is_proc_macro_crate && attr::contains_name(&item.attrs, sym::macro_export) {
+ if self.is_proc_macro_crate && self.sess.contains_name(&item.attrs, sym::macro_export) {
let msg =
"cannot export macro_rules! macros from a `proc-macro` crate type currently";
self.handler.span_err(self.source_map.guess_head_span(item.span), msg);
let mut found_attr: Option<&'a ast::Attribute> = None;
for attr in &item.attrs {
- if is_proc_macro_attr(&attr) {
+ if self.sess.is_proc_macro_attr(&attr) {
if let Some(prev_attr) = found_attr {
let prev_item = prev_attr.get_normal_item();
let item = attr.get_normal_item();
return;
}
- if attr.check_name(sym::proc_macro_derive) {
+ if self.sess.check_name(attr, sym::proc_macro_derive) {
self.collect_custom_derive(item, attr);
- } else if attr.check_name(sym::proc_macro_attribute) {
+ } else if self.sess.check_name(attr, sym::proc_macro_attribute) {
self.collect_attr_proc_macro(item);
- } else if attr.check_name(sym::proc_macro) {
+ } else if self.sess.check_name(attr, sym::proc_macro) {
self.collect_bang_proc_macro(item);
};
+use rustc_ast::ast;
use rustc_ast::ptr::P;
-use rustc_ast::{ast, attr};
use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::ExpansionConfig;
-use rustc_session::parse::ParseSess;
+use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::hygiene::AstPass;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
pub fn inject(
mut krate: ast::Crate,
resolver: &mut dyn ResolverExpand,
- sess: &ParseSess,
+ sess: &Session,
alt_std_name: Option<Symbol>,
) -> (ast::Crate, Option<Symbol>) {
- let rust_2018 = sess.edition >= Edition::Edition2018;
+ let rust_2018 = sess.parse_sess.edition >= Edition::Edition2018;
// the first name in this list is the crate name of the crate with the prelude
- let names: &[Symbol] = if attr::contains_name(&krate.attrs, sym::no_core) {
+ let names: &[Symbol] = if sess.contains_name(&krate.attrs, sym::no_core) {
return (krate, None);
- } else if attr::contains_name(&krate.attrs, sym::no_std) {
- if attr::contains_name(&krate.attrs, sym::compiler_builtins) {
+ } else if sess.contains_name(&krate.attrs, sym::no_std) {
+ if sess.contains_name(&krate.attrs, sym::compiler_builtins) {
&[sym::core]
} else {
&[sym::core, sym::compiler_builtins]
use rustc_ast::attr;
use rustc_ast_pretty::pprust;
use rustc_expand::base::*;
+use rustc_session::Session;
use rustc_span::source_map::respan;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
};
if let ast::ItemKind::MacCall(_) = item.kind {
- cx.parse_sess.span_diagnostic.span_warn(
+ cx.sess.parse_sess.span_diagnostic.span_warn(
item.span,
"`#[test]` attribute should not be used on macros. Use `#[cfg(test)]` instead.",
);
),
),
// ignore: true | false
- field("ignore", cx.expr_bool(sp, should_ignore(&item))),
+ field(
+ "ignore",
+ cx.expr_bool(sp, should_ignore(&cx.sess, &item)),
+ ),
// allow_fail: true | false
- field("allow_fail", cx.expr_bool(sp, should_fail(&item))),
+ field(
+ "allow_fail",
+ cx.expr_bool(sp, should_fail(&cx.sess, &item)),
+ ),
// should_panic: ...
field(
"should_panic",
Yes(Option<Symbol>),
}
-fn should_ignore(i: &ast::Item) -> bool {
- attr::contains_name(&i.attrs, sym::ignore)
+fn should_ignore(sess: &Session, i: &ast::Item) -> bool {
+ sess.contains_name(&i.attrs, sym::ignore)
}
-fn should_fail(i: &ast::Item) -> bool {
- attr::contains_name(&i.attrs, sym::allow_fail)
+fn should_fail(sess: &Session, i: &ast::Item) -> bool {
+ sess.contains_name(&i.attrs, sym::allow_fail)
}
fn should_panic(cx: &ExtCtxt<'_>, i: &ast::Item) -> ShouldPanic {
- match attr::find_by_name(&i.attrs, sym::should_panic) {
+ match cx.sess.find_by_name(&i.attrs, sym::should_panic) {
Some(attr) => {
- let sd = &cx.parse_sess.span_diagnostic;
+ let sd = &cx.sess.parse_sess.span_diagnostic;
match attr.meta_item_list() {
// Handle #[should_panic(expected = "foo")]
}
fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
- let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
- let sd = &cx.parse_sess.span_diagnostic;
+ let has_should_panic_attr = cx.sess.contains_name(&i.attrs, sym::should_panic);
+ let sd = &cx.sess.parse_sess.span_diagnostic;
if let ast::ItemKind::Fn(_, ref sig, ref generics, _) = i.kind {
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
};
if !has_sig {
- cx.parse_sess.span_diagnostic.span_err(
+ cx.sess.parse_sess.span_diagnostic.span_err(
i.span,
"functions used as benches must have \
signature `fn(&mut Bencher) -> impl Termination`",
use rustc_ast::ast;
use rustc_ast::attr;
-use rustc_ast::entry::{self, EntryPointType};
+use rustc_ast::entry::EntryPointType;
use rustc_ast::mut_visit::{ExpectOne, *};
use rustc_ast::ptr::P;
use rustc_expand::base::{ExtCtxt, ResolverExpand};
use rustc_expand::expand::{AstFragment, ExpansionConfig};
use rustc_feature::Features;
-use rustc_session::parse::ParseSess;
+use rustc_session::Session;
use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
use rustc_span::source_map::respan;
use rustc_span::symbol::{sym, Ident, Symbol};
// Traverse the crate, collecting all the test functions, eliding any
// existing main functions, and synthesizing a main test harness
-pub fn inject(
- sess: &ParseSess,
- resolver: &mut dyn ResolverExpand,
- should_test: bool,
- krate: &mut ast::Crate,
- span_diagnostic: &rustc_errors::Handler,
- features: &Features,
- panic_strategy: PanicStrategy,
- platform_panic_strategy: PanicStrategy,
- enable_panic_abort_tests: bool,
-) {
+pub fn inject(sess: &Session, resolver: &mut dyn ResolverExpand, krate: &mut ast::Crate) {
+ let span_diagnostic = sess.diagnostic();
+ let panic_strategy = sess.panic_strategy();
+ let platform_panic_strategy = sess.target.target.options.panic_strategy;
+
// Check for #![reexport_test_harness_main = "some_name"] which gives the
// main test function the name `some_name` without hygiene. This needs to be
// unconditional, so that the attribute is still marked as used in
// non-test builds.
let reexport_test_harness_main =
- attr::first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
+ sess.first_attr_value_str_by_name(&krate.attrs, sym::reexport_test_harness_main);
// Do this here so that the test_runner crate attribute gets marked as used
// even in non-test builds
- let test_runner = get_test_runner(span_diagnostic, &krate);
+ let test_runner = get_test_runner(sess, span_diagnostic, &krate);
- if should_test {
- let panic_strategy = match (panic_strategy, enable_panic_abort_tests) {
+ if sess.opts.test {
+ let panic_strategy = match (panic_strategy, sess.opts.debugging_opts.panic_abort_tests) {
(PanicStrategy::Abort, true) => PanicStrategy::Abort,
- (PanicStrategy::Abort, false) if panic_strategy == platform_panic_strategy => {
- // Silently allow compiling with panic=abort on these platforms,
- // but with old behavior (abort if a test fails).
- PanicStrategy::Unwind
- }
(PanicStrategy::Abort, false) => {
- span_diagnostic.err(
- "building tests with panic=abort is not supported \
- without `-Zpanic_abort_tests`",
- );
+ if panic_strategy == platform_panic_strategy {
+ // Silently allow compiling with panic=abort on these platforms,
+ // but with old behavior (abort if a test fails).
+ } else {
+ span_diagnostic.err(
+ "building tests with panic=abort is not supported \
+ without `-Zpanic_abort_tests`",
+ );
+ }
PanicStrategy::Unwind
}
(PanicStrategy::Unwind, _) => PanicStrategy::Unwind,
resolver,
reexport_test_harness_main,
krate,
- features,
+ &sess.features_untracked(),
panic_strategy,
test_runner,
)
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
let mut item = i.into_inner();
- if is_test_case(&item) {
+ if is_test_case(&self.cx.ext_cx.sess, &item) {
debug!("this is a test item");
let test = Test { span: item.span, ident: item.ident };
}
}
+// Beware, this is duplicated in librustc_passes/entry.rs (with
+// `rustc_hir::Item`), so make sure to keep them in sync.
+fn entry_point_type(sess: &Session, item: &ast::Item, depth: usize) -> EntryPointType {
+ match item.kind {
+ ast::ItemKind::Fn(..) => {
+ if sess.contains_name(&item.attrs, sym::start) {
+ EntryPointType::Start
+ } else if sess.contains_name(&item.attrs, sym::main) {
+ EntryPointType::MainAttr
+ } else if item.ident.name == sym::main {
+ if depth == 1 {
+ // This is a top-level function so can be 'main'
+ EntryPointType::MainNamed
+ } else {
+ EntryPointType::OtherMain
+ }
+ } else {
+ EntryPointType::None
+ }
+ }
+ _ => EntryPointType::None,
+ }
+}
/// A folder used to remove any entry points (like fn main) because the harness
/// generator will provide its own
-struct EntryPointCleaner {
+struct EntryPointCleaner<'a> {
// Current depth in the ast
+ sess: &'a Session,
depth: usize,
def_site: Span,
}
-impl MutVisitor for EntryPointCleaner {
+impl<'a> MutVisitor for EntryPointCleaner<'a> {
fn flat_map_item(&mut self, i: P<ast::Item>) -> SmallVec<[P<ast::Item>; 1]> {
self.depth += 1;
let item = noop_flat_map_item(i, self).expect_one("noop did something");
// Remove any #[main] or #[start] from the AST so it doesn't
// clash with the one we're going to add, but mark it as
// #[allow(dead_code)] to avoid printing warnings.
- let item = match entry::entry_point_type(&item, self.depth) {
+ let item = match entry_point_type(self.sess, &item, self.depth) {
EntryPointType::MainNamed | EntryPointType::MainAttr | EntryPointType::Start => item
.map(|ast::Item { id, ident, attrs, kind, vis, span, tokens }| {
let allow_ident = Ident::new(sym::allow, self.def_site);
let allow_dead_code = attr::mk_attr_outer(allow_dead_code_item);
let attrs = attrs
.into_iter()
- .filter(|attr| !attr.check_name(sym::main) && !attr.check_name(sym::start))
+ .filter(|attr| {
+ !self.sess.check_name(attr, sym::main)
+ && !self.sess.check_name(attr, sym::start)
+ })
.chain(iter::once(allow_dead_code))
.collect();
/// Crawl over the crate, inserting test reexports and the test main function
fn generate_test_harness(
- sess: &ParseSess,
+ sess: &Session,
resolver: &mut dyn ResolverExpand,
reexport_test_harness_main: Option<Symbol>,
krate: &mut ast::Crate,
let def_site = DUMMY_SP.with_def_site_ctxt(expn_id);
// Remove the entry points
- let mut cleaner = EntryPointCleaner { depth: 0, def_site };
+ let mut cleaner = EntryPointCleaner { sess, depth: 0, def_site };
cleaner.visit_crate(krate);
let cx = TestCtxt {
)
}
-fn is_test_case(i: &ast::Item) -> bool {
- attr::contains_name(&i.attrs, sym::rustc_test_marker)
+fn is_test_case(sess: &Session, i: &ast::Item) -> bool {
+ sess.contains_name(&i.attrs, sym::rustc_test_marker)
}
-fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast::Path> {
- let test_attr = attr::find_by_name(&krate.attrs, sym::test_runner)?;
+fn get_test_runner(
+ sess: &Session,
+ sd: &rustc_errors::Handler,
+ krate: &ast::Crate,
+) -> Option<ast::Path> {
+ let test_attr = sess.find_by_name(&krate.attrs, sym::test_runner)?;
let meta_list = test_attr.meta_item_list()?;
let span = test_attr.span;
match &*meta_list {
// All the built-in macro attributes are "words" at the moment.
let template = AttributeTemplate { word: true, ..Default::default() };
let attr = ecx.attribute(meta_item.clone());
- validate_attr::check_builtin_attribute(ecx.parse_sess, &attr, name, template);
+ validate_attr::check_builtin_attribute(&ecx.sess.parse_sess, &attr, name, template);
}
debug!("get_static: sym={} attrs={:?}", sym, attrs);
for attr in attrs {
- if attr.check_name(sym::thread_local) {
+ if self.tcx.sess.check_name(attr, sym::thread_local) {
llvm::set_thread_local_mode(g, self.tls_model);
}
}
use llvm::coverageinfo::CounterMappingRegion;
use rustc_codegen_ssa::coverageinfo::map::{Counter, CounterExpression, Region};
use rustc_codegen_ssa::traits::{BaseTypeMethods, ConstMethods};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_llvm::RustString;
use tracing::debug;
}
struct CoverageMapGenerator {
- filenames: Vec<CString>,
- filename_to_index: FxHashMap<CString, u32>,
+ filenames: FxIndexSet<CString>,
}
impl CoverageMapGenerator {
fn new() -> Self {
- Self { filenames: Vec::new(), filename_to_index: FxHashMap::default() }
+ Self { filenames: FxIndexSet::default() }
}
/// Using the `expressions` and `counter_regions` collected for the current function, generate
let c_filename =
CString::new(file_name).expect("null error converting filename to C string");
debug!(" file_id: {} = '{:?}'", current_file_id, c_filename);
- let filenames_index = match self.filename_to_index.get(&c_filename) {
- Some(index) => *index,
- None => {
- let index = self.filenames.len() as u32;
- self.filenames.push(c_filename.clone());
- self.filename_to_index.insert(c_filename.clone(), index);
- index
- }
- };
- virtual_file_mapping.push(filenames_index);
+ let (filenames_index, _) = self.filenames.insert_full(c_filename);
+ virtual_file_mapping.push(filenames_index as u32);
}
mapping_regions.push(CounterMappingRegion::code_region(
counter,
}
}
-pub(crate) fn write_filenames_section_to_buffer(filenames: &Vec<CString>, buffer: &RustString) {
- let c_str_vec = filenames.iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
+pub(crate) fn write_filenames_section_to_buffer<'a>(
+ filenames: impl IntoIterator<Item = &'a CString>,
+ buffer: &RustString,
+) {
+ let c_str_vec = filenames.into_iter().map(|cstring| cstring.as_ptr()).collect::<Vec<_>>();
unsafe {
llvm::LLVMRustCoverageWriteFilenamesSectionToBuffer(
c_str_vec.as_ptr(),
use rustc_middle::bug;
use rustc_session::config::DebugInfo;
-use rustc_ast::attr;
use rustc_span::symbol::sym;
/// Inserts a side-effect free instruction sequence that makes sure that the
}
pub fn needs_gdb_debug_scripts_section(cx: &CodegenCx<'_, '_>) -> bool {
- let omit_gdb_pretty_printer_section =
- attr::contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
+ let omit_gdb_pretty_printer_section = cx
+ .tcx
+ .sess
+ .contains_name(&cx.tcx.hir().krate_attrs(), sym::omit_gdb_pretty_printer_section);
!omit_gdb_pretty_printer_section
&& cx.sess().opts.debuginfo != DebugInfo::None
fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType {
debug!("param_type_metadata: {:?}", t);
let name = format!("{:?}", t);
- return unsafe {
+ unsafe {
llvm::LLVMRustDIBuilderCreateBasicType(
DIB(cx),
name.as_ptr().cast(),
Size::ZERO.bits(),
DW_ATE_unsigned,
)
- };
+ }
}
pub fn compile_unit_metadata(
Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)),
// FIXME: Find some heuristic for "native mingw toolchain is available",
// likely based on `get_crt_libs_path` (https://github.com/rust-lang/rust/pull/67429).
- Some(CrtObjectsFallback::Mingw) => sess.target.target.target_vendor != "uwp",
+ Some(CrtObjectsFallback::Mingw) => {
+ sess.host == sess.target.target && sess.target.target.target_vendor != "uwp"
+ }
// FIXME: Figure out cases in which WASM needs to link with a native toolchain.
Some(CrtObjectsFallback::Wasm) => true,
None => false,
use crate::traits::*;
use jobserver::{Acquired, Client};
-use rustc_ast::attr;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::profiling::TimingGuard;
let crate_name = tcx.crate_name(LOCAL_CRATE);
let crate_hash = tcx.crate_hash(LOCAL_CRATE);
- let no_builtins = attr::contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins);
+ let no_builtins = tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::no_builtins);
let is_compiler_builtins =
- attr::contains_name(&tcx.hir().krate().item.attrs, sym::compiler_builtins);
- let subsystem =
- attr::first_attr_value_str_by_name(&tcx.hir().krate().item.attrs, sym::windows_subsystem);
+ tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::compiler_builtins);
+ let subsystem = tcx
+ .sess
+ .first_attr_value_str_by_name(&tcx.hir().krate().item.attrs, sym::windows_subsystem);
let windows_subsystem = subsystem.map(|subsystem| {
if subsystem != sym::windows && subsystem != sym::console {
tcx.sess.fatal(&format!(
let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir");
for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
- let path = module.object.as_ref().map(|path| path.clone());
+ let path = module.object.as_ref().cloned();
if let Some((id, product)) =
copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, &path)
bx.sub(tag, bx.cx().const_uint_big(niche_llty, niche_start))
};
let relative_max = niche_variants.end().as_u32() - niche_variants.start().as_u32();
- let is_niche = {
- let relative_max = if relative_max == 0 {
- // Avoid calling `const_uint`, which wouldn't work for pointers.
- // FIXME(eddyb) check the actual primitive type here.
- bx.cx().const_null(niche_llty)
- } else {
- bx.cx().const_uint(niche_llty, relative_max as u64)
- };
+ let is_niche = if relative_max == 0 {
+ // Avoid calling `const_uint`, which wouldn't work for pointers.
+ // Also use canonical == 0 instead of non-canonical u<= 0.
+ // FIXME(eddyb) check the actual primitive type here.
+ bx.icmp(IntPredicate::IntEQ, relative_discr, bx.cx().const_null(niche_llty))
+ } else {
+ let relative_max = bx.cx().const_uint(niche_llty, relative_max as u64);
bx.icmp(IntPredicate::IntULE, relative_discr, relative_max)
};
[dependencies]
ena = "0.14"
-indexmap = "1"
+indexmap = "1.5.1"
tracing = "0.1"
jobserver_crate = { version = "0.1.13", package = "jobserver" }
lazy_static = "1"
-use crate::fx::FxHashMap;
+use crate::fx::FxIndexSet;
use crate::stable_hasher::{HashStable, StableHasher};
use crate::sync::Lock;
use rustc_index::bit_set::BitMatrix;
#[derive(Clone, Debug)]
pub struct TransitiveRelation<T: Eq + Hash> {
// List of elements. This is used to map from a T to a usize.
- elements: Vec<T>,
-
- // Maps each element to an index.
- map: FxHashMap<T, Index>,
+ elements: FxIndexSet<T>,
// List of base edges in the graph. Require to compute transitive
// closure.
fn default() -> Self {
TransitiveRelation {
elements: Default::default(),
- map: Default::default(),
edges: Default::default(),
closure: Default::default(),
}
}
fn index(&self, a: &T) -> Option<Index> {
- self.map.get(a).cloned()
+ self.elements.get_index_of(a).map(Index)
}
fn add_index(&mut self, a: T) -> Index {
- let &mut TransitiveRelation { ref mut elements, ref mut closure, ref mut map, .. } = self;
-
- *map.entry(a.clone()).or_insert_with(|| {
- elements.push(a);
-
+ let (index, added) = self.elements.insert_full(a);
+ if added {
// if we changed the dimensions, clear the cache
- *closure.get_mut() = None;
-
- Index(elements.len() - 1)
- })
+ *self.closure.get_mut() = None;
+ }
+ Index(index)
}
/// Applies the (partial) function to each edge and returns a new
{
fn decode<D: Decoder>(d: &mut D) -> Result<Self, D::Error> {
d.read_struct("TransitiveRelation", 2, |d| {
- let elements: Vec<T> = d.read_struct_field("elements", 0, |d| Decodable::decode(d))?;
- let edges = d.read_struct_field("edges", 1, |d| Decodable::decode(d))?;
- let map = elements
- .iter()
- .enumerate()
- .map(|(index, elem)| (elem.clone(), Index(index)))
- .collect();
- Ok(TransitiveRelation { elements, edges, map, closure: Lock::new(None) })
+ Ok(TransitiveRelation {
+ elements: d.read_struct_field("elements", 0, |d| Decodable::decode(d))?,
+ edges: d.read_struct_field("edges", 1, |d| Decodable::decode(d))?,
+ closure: Lock::new(None),
+ })
})
}
}
let TransitiveRelation {
ref elements,
ref edges,
- // "map" is just a copy of elements vec
- map: _,
// "closure" is just a copy of the data above
closure: _,
} = *self;
let t_outputs = rustc_interface::util::build_output_filenames(
input, odir, ofile, attrs, sess,
);
- let id = rustc_session::output::find_crate_name(Some(sess), attrs, input);
+ let id = rustc_session::output::find_crate_name(sess, attrs, input);
if *req == PrintRequest::CrateName {
println!("{}", id);
continue;
```compile_fail,E0271
trait Trait { type AssociatedType; }
-fn foo<T>(t: T) where T: Trait<AssociatedType=u32> {
- println!("in foo");
-}
-
-impl Trait for i8 { type AssociatedType = &'static str; }
-
-foo(3_i8);
-```
-
-This is because of a type mismatch between the associated type of some
-trait (e.g., `T::Bar`, where `T` implements `trait Quux { type Bar; }`)
-and another type `U` that is required to be equal to `T::Bar`, but is not.
-Examples follow.
-
-Here is that same example again, with some explanatory comments:
-
-```compile_fail,E0271
-trait Trait { type AssociatedType; }
-
fn foo<T>(t: T) where T: Trait<AssociatedType=u32> {
// ~~~~~~~~ ~~~~~~~~~~~~~~~~~~
// | |
// therefore the type-checker complains with this error code.
```
-To avoid those issues, you have to make the types match correctly.
-So we can fix the previous examples like this:
-
+The issue can be resolved by changing the associated type:
+1) in the `foo` implementation:
```
-// Basic Example:
trait Trait { type AssociatedType; }
fn foo<T>(t: T) where T: Trait<AssociatedType = &'static str> {
impl Trait for i8 { type AssociatedType = &'static str; }
foo(3_i8);
+```
-// For-Loop Example:
-let vs = vec![1, 2, 3, 4];
-for v in &vs {
- match v {
- &1 => {}
- _ => {}
- }
+2) in the `Trait` implementation for `i8`:
+```
+trait Trait { type AssociatedType; }
+
+fn foo<T>(t: T) where T: Trait<AssociatedType = u32> {
+ println!("in foo");
}
+
+impl Trait for i8 { type AssociatedType = u32; }
+
+foo(3_i8);
```
```compile_fail,E0502
fn bar(x: &mut i32) {}
fn foo(a: &mut i32) {
- let ref y = a; // a is borrowed as immutable.
+ let y = &a; // a is borrowed as immutable.
bar(a); // error: cannot borrow `*a` as mutable because `a` is also borrowed
// as immutable
println!("{}", y);
fn bar(x: &mut i32) {}
fn foo(a: &mut i32) {
bar(a);
- let ref y = a; // ok!
+ let y = &a; // ok!
println!("{}", y);
}
```
-Return types cannot be `dyn Trait`s as they must be `Sized`.
+An unboxed trait object was used as a return value.
Erroneous code example:
// Having the trait `T` as return type is invalid because
// unboxed trait objects do not have a statically known size:
-fn foo() -> dyn T {
+fn foo() -> dyn T { // error!
S(42)
}
```
+Return types cannot be `dyn Trait`s as they must be `Sized`.
+
To avoid the error there are a couple of options.
If there is a single type involved, you can use [`impl Trait`]:
# }
// The compiler will select `S(usize)` as the materialized return type of this
// function, but callers will only know that the return type implements `T`.
-fn foo() -> impl T {
+fn foo() -> impl T { // ok!
S(42)
}
```
// This now returns a "trait object" and callers are only be able to access
// associated items from `T`.
-fn foo(x: bool) -> Box<dyn T> {
+fn foo(x: bool) -> Box<dyn T> { // ok!
if x {
Box::new(S(42))
} else {
-Generic arguments must be provided in the same order as the corresponding
+Generic arguments were not provided in the same order as the corresponding
generic parameters are declared.
Erroneous code example:
```
The argument order should be changed to match the parameter declaration
-order, as in the following.
+order, as in the following:
```
struct S<'a, T>(&'a T);
-Negative impls are not allowed to have any items. Negative impls
-declare that a trait is **not** implemented (and never will be) and
-hence there is no need to specify the values for trait methods or
-other items.
+An item was added on a negative impl.
+
+Erroneous code example:
+
+```compile_fail,E0749
+# #![feature(negative_impls)]
+trait MyTrait {
+ type Foo;
+}
+
+impl !MyTrait for u32 {
+ type Foo = i32; // error!
+}
+# fn main() {}
+```
+
+Negative impls are not allowed to have any items. Negative impls declare that a
+trait is **not** implemented (and never will be) and hence there is no need to
+specify the values for trait methods or other items.
-Negative impls cannot be default impls. A default impl supplies
-default values for the items within to be used by other impls, whereas
-a negative impl declares that there are no other impls. These don't
-make sense to combine.
+A negative impl was made default impl.
+
+Erroneous code example:
+
+```compile_fail,E0750
+# #![feature(negative_impls)]
+# #![feature(specialization)]
+trait MyTrait {
+ type Foo;
+}
+
+default impl !MyTrait for u32 {} // error!
+# fn main() {}
+```
+
+Negative impls cannot be default impls. A default impl supplies default values
+for the items within to be used by other impls, whereas a negative impl declares
+that there are no other impls. Combining it does not make sense.
use rustc_data_structures::sync::{self, Lrc};
use rustc_errors::{DiagnosticBuilder, ErrorReported};
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
-use rustc_session::{parse::ParseSess, Limit};
+use rustc_session::{parse::ParseSess, Limit, Session};
use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::edition::Edition;
use rustc_span::hygiene::{AstPass, ExpnData, ExpnId, ExpnKind};
/// Constructs a syntax extension with the given properties
/// and other properties converted from attributes.
pub fn new(
- sess: &ParseSess,
+ sess: &Session,
kind: SyntaxExtensionKind,
span: Span,
helper_attrs: Vec<Symbol>,
name: Symbol,
attrs: &[ast::Attribute],
) -> SyntaxExtension {
- let allow_internal_unstable = attr::allow_internal_unstable(&attrs, &sess.span_diagnostic)
+ let allow_internal_unstable = attr::allow_internal_unstable(sess, &attrs)
.map(|features| features.collect::<Vec<Symbol>>().into());
let mut local_inner_macros = false;
- if let Some(macro_export) = attr::find_by_name(attrs, sym::macro_export) {
+ if let Some(macro_export) = sess.find_by_name(attrs, sym::macro_export) {
if let Some(l) = macro_export.meta_item_list() {
local_inner_macros = attr::list_contains_name(&l, sym::local_inner_macros);
}
}
- let is_builtin = attr::contains_name(attrs, sym::rustc_builtin_macro);
+ let is_builtin = sess.contains_name(attrs, sym::rustc_builtin_macro);
let (stability, const_stability) = attr::find_stability(&sess, attrs, span);
if const_stability.is_some() {
- sess.span_diagnostic.span_err(span, "macros cannot have const stability attributes");
+ sess.parse_sess
+ .span_diagnostic
+ .span_err(span, "macros cannot have const stability attributes");
}
SyntaxExtension {
kind,
span,
allow_internal_unstable,
- allow_internal_unsafe: attr::contains_name(attrs, sym::allow_internal_unsafe),
+ allow_internal_unsafe: sess.contains_name(attrs, sym::allow_internal_unsafe),
local_inner_macros,
stability,
deprecation: attr::find_deprecation(&sess, attrs, span),
/// when a macro expansion occurs, the resulting nodes have the `backtrace()
/// -> expn_data` of their expansion context stored into their span.
pub struct ExtCtxt<'a> {
- pub parse_sess: &'a ParseSess,
+ pub sess: &'a Session,
pub ecfg: expand::ExpansionConfig<'a>,
pub reduced_recursion_limit: Option<Limit>,
pub root_path: PathBuf,
impl<'a> ExtCtxt<'a> {
pub fn new(
- parse_sess: &'a ParseSess,
+ sess: &'a Session,
ecfg: expand::ExpansionConfig<'a>,
resolver: &'a mut dyn ResolverExpand,
extern_mod_loaded: Option<&'a dyn Fn(&ast::Crate)>,
) -> ExtCtxt<'a> {
ExtCtxt {
- parse_sess,
+ sess,
ecfg,
reduced_recursion_limit: None,
resolver,
expand::MacroExpander::new(self, true)
}
pub fn new_parser_from_tts(&self, stream: TokenStream) -> parser::Parser<'a> {
- rustc_parse::stream_to_parser(self.parse_sess, stream, MACRO_ARGUMENTS)
+ rustc_parse::stream_to_parser(&self.sess.parse_sess, stream, MACRO_ARGUMENTS)
}
pub fn source_map(&self) -> &'a SourceMap {
- self.parse_sess.source_map()
+ self.sess.parse_sess.source_map()
}
pub fn parse_sess(&self) -> &'a ParseSess {
- self.parse_sess
+ &self.sess.parse_sess
}
pub fn call_site(&self) -> Span {
self.current_expansion.id.expn_data().call_site
}
pub fn struct_span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> DiagnosticBuilder<'a> {
- self.parse_sess.span_diagnostic.struct_span_err(sp, msg)
+ self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg)
}
/// Emit `msg` attached to `sp`, without immediately stopping
/// Compilation will be stopped in the near future (at the end of
/// the macro expansion phase).
pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
- self.parse_sess.span_diagnostic.span_err(sp, msg);
+ self.sess.parse_sess.span_diagnostic.span_err(sp, msg);
}
pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
- self.parse_sess.span_diagnostic.span_warn(sp, msg);
+ self.sess.parse_sess.span_diagnostic.span_warn(sp, msg);
}
pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
- self.parse_sess.span_diagnostic.span_bug(sp, msg);
+ self.sess.parse_sess.span_diagnostic.span_bug(sp, msg);
}
pub fn trace_macros_diag(&mut self) {
for (sp, notes) in self.expansions.iter() {
- let mut db = self.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro");
+ let mut db = self.sess.parse_sess.span_diagnostic.span_note_diag(*sp, "trace_macro");
for note in notes {
db.note(note);
}
self.expansions.clear();
}
pub fn bug(&self, msg: &str) -> ! {
- self.parse_sess.span_diagnostic.bug(msg);
+ self.sess.parse_sess.span_diagnostic.bug(msg);
}
pub fn trace_macros(&self) -> bool {
self.ecfg.trace_mac
ACCEPTED_FEATURES, ACTIVE_FEATURES, REMOVED_FEATURES, STABLE_REMOVED_FEATURES,
};
use rustc_parse::{parse_in, validate_attr};
-use rustc_session::parse::{feature_err, ParseSess};
+use rustc_session::parse::feature_err;
+use rustc_session::Session;
use rustc_span::edition::{Edition, ALL_EDITIONS};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
/// A folder that strips out items that do not belong in the current configuration.
pub struct StripUnconfigured<'a> {
- pub sess: &'a ParseSess,
+ pub sess: &'a Session,
pub features: Option<&'a Features>,
}
fn get_features(
+ sess: &Session,
span_handler: &Handler,
krate_attrs: &[ast::Attribute],
- crate_edition: Edition,
- allow_features: &Option<Vec<String>>,
) -> Features {
fn feature_removed(span_handler: &Handler, span: Span, reason: Option<&str>) {
let mut err = struct_span_err!(span_handler, span, E0557, "feature has been removed");
let mut features = Features::default();
let mut edition_enabled_features = FxHashMap::default();
+ let crate_edition = sess.edition();
for &edition in ALL_EDITIONS {
if edition <= crate_edition {
// Process the edition umbrella feature-gates first, to ensure
// `edition_enabled_features` is completed before it's queried.
for attr in krate_attrs {
- if !attr.check_name(sym::feature) {
+ if !sess.check_name(attr, sym::feature) {
continue;
}
}
for attr in krate_attrs {
- if !attr.check_name(sym::feature) {
+ if !sess.check_name(attr, sym::feature) {
continue;
}
continue;
}
- if let Some(allowed) = allow_features.as_ref() {
+ if let Some(allowed) = sess.opts.debugging_opts.allow_features.as_ref() {
if allowed.iter().find(|&f| name.as_str() == *f).is_none() {
struct_span_err!(
span_handler,
}
// `cfg_attr`-process the crate's attributes and compute the crate's features.
-pub fn features(
- mut krate: ast::Crate,
- sess: &ParseSess,
- edition: Edition,
- allow_features: &Option<Vec<String>>,
-) -> (ast::Crate, Features) {
+pub fn features(sess: &Session, mut krate: ast::Crate) -> (ast::Crate, Features) {
let mut strip_unconfigured = StripUnconfigured { sess, features: None };
let unconfigured_attrs = krate.attrs.clone();
- let diag = &sess.span_diagnostic;
+ let diag = &sess.parse_sess.span_diagnostic;
let err_count = diag.err_count();
let features = match strip_unconfigured.configure(krate.attrs) {
None => {
}
Some(attrs) => {
krate.attrs = attrs;
- let features = get_features(diag, &krate.attrs, edition, allow_features);
+ let features = get_features(sess, diag, &krate.attrs);
if err_count == diag.err_count() {
// Avoid reconfiguring malformed `cfg_attr`s.
strip_unconfigured.features = Some(&features);
}
// At this point we know the attribute is considered used.
- attr::mark_used(&attr);
+ self.sess.mark_attr_used(&attr);
- if !attr::cfg_matches(&cfg_predicate, self.sess, self.features) {
+ if !attr::cfg_matches(&cfg_predicate, &self.sess.parse_sess, self.features) {
return vec![];
}
match attr.get_normal_item().args {
ast::MacArgs::Delimited(dspan, delim, ref tts) if !tts.is_empty() => {
let msg = "wrong `cfg_attr` delimiters";
- validate_attr::check_meta_bad_delim(self.sess, dspan, delim, msg);
- match parse_in(self.sess, tts.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
+ validate_attr::check_meta_bad_delim(&self.sess.parse_sess, dspan, delim, msg);
+ match parse_in(&self.sess.parse_sess, tts.clone(), "`cfg_attr` input", |p| {
+ p.parse_cfg_attr()
+ }) {
Ok(r) => return Some(r),
Err(mut e) => {
e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
fn error_malformed_cfg_attr_missing(&self, span: Span) {
self.sess
+ .parse_sess
.span_diagnostic
.struct_span_err(span, "malformed `cfg_attr` attribute input")
.span_suggestion(
/// Determines if a node with the given attributes should be included in this configuration.
pub fn in_cfg(&self, attrs: &[Attribute]) -> bool {
attrs.iter().all(|attr| {
- if !is_cfg(attr) {
+ if !is_cfg(self.sess, attr) {
return true;
}
- let meta_item = match validate_attr::parse_meta(self.sess, attr) {
+ let meta_item = match validate_attr::parse_meta(&self.sess.parse_sess, attr) {
Ok(meta_item) => meta_item,
Err(mut err) => {
err.emit();
}
};
let error = |span, msg, suggestion: &str| {
- let mut err = self.sess.span_diagnostic.struct_span_err(span, msg);
+ let mut err = self.sess.parse_sess.span_diagnostic.struct_span_err(span, msg);
if !suggestion.is_empty() {
err.span_suggestion(
span,
Some([]) => error(span, "`cfg` predicate is not specified", ""),
Some([_, .., l]) => error(l.span(), "multiple `cfg` predicates are specified", ""),
Some([single]) => match single.meta_item() {
- Some(meta_item) => attr::cfg_matches(meta_item, self.sess, self.features),
+ Some(meta_item) => {
+ attr::cfg_matches(meta_item, &self.sess.parse_sess, self.features)
+ }
None => error(single.span(), "`cfg` predicate key cannot be a literal", ""),
},
}
pub fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
if !self.features.map(|features| features.stmt_expr_attributes).unwrap_or(true) {
let mut err = feature_err(
- self.sess,
+ &self.sess.parse_sess,
sym::stmt_expr_attributes,
attr.span,
"attributes on expressions are experimental",
//
// N.B., this is intentionally not part of the visit_expr() function
// in order for filter_map_expr() to be able to avoid this check
- if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(a)) {
+ if let Some(attr) = expr.attrs().iter().find(|a| is_cfg(self.sess, a)) {
let msg = "removing an expression is not supported in this position";
- self.sess.span_diagnostic.span_err(attr.span, msg);
+ self.sess.parse_sess.span_diagnostic.span_err(attr.span, msg);
}
self.process_cfg_attrs(expr)
}
}
-fn is_cfg(attr: &Attribute) -> bool {
- attr.check_name(sym::cfg)
+fn is_cfg(sess: &Session, attr: &Attribute) -> bool {
+ sess.check_name(attr, sym::cfg)
}
}
fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) {
- let attr = attr::find_by_name(item.attrs(), sym::derive);
+ let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive);
let span = attr.map_or(item.span(), |attr| attr.span);
let mut err = self
.cx
let invocations = {
let mut collector = InvocationCollector {
- cfg: StripUnconfigured {
- sess: self.cx.parse_sess,
- features: self.cx.ecfg.features,
- },
+ cfg: StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features },
cx: self.cx,
invocations: Vec::new(),
monotonic: self.monotonic,
}
fn fully_configure(&mut self, item: Annotatable) -> Annotatable {
- let mut cfg =
- StripUnconfigured { sess: self.cx.parse_sess, features: self.cx.ecfg.features };
+ let mut cfg = StripUnconfigured { sess: &self.cx.sess, features: self.cx.ecfg.features };
// Since the item itself has already been configured by the InvocationCollector,
// we know that fold result vector will contain exactly one element
match item {
SyntaxExtensionKind::Attr(expander) => {
self.gate_proc_macro_input(&item);
self.gate_proc_macro_attr_item(span, &item);
- let tokens = item.into_tokens(self.cx.parse_sess);
+ let tokens = item.into_tokens(&self.cx.sess.parse_sess);
let attr_item = attr.unwrap_normal_item();
if let MacArgs::Eq(..) = attr_item.args {
self.cx.span_err(span, "key-value macro attributes are not supported");
self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span)
}
SyntaxExtensionKind::LegacyAttr(expander) => {
- match validate_attr::parse_meta(self.cx.parse_sess, &attr) {
+ match validate_attr::parse_meta(&self.cx.sess.parse_sess, &attr) {
Ok(meta) => {
let items = match expander.expand(self.cx, span, &meta, item) {
ExpandResult::Ready(items) => items,
}
}
SyntaxExtensionKind::NonMacroAttr { mark_used } => {
- attr::mark_known(&attr);
+ self.cx.sess.mark_attr_known(&attr);
if *mark_used {
- attr::mark_used(&attr);
+ self.cx.sess.mark_attr_used(&attr);
}
item.visit_attrs(|attrs| attrs.push(attr));
fragment_kind.expect_from_annotatables(iter::once(item))
return;
}
feature_err(
- self.cx.parse_sess,
+ &self.cx.sess.parse_sess,
sym::proc_macro_hygiene,
span,
&format!("custom attributes cannot be applied to {}", kind),
}
if !self.cx.ecfg.proc_macro_hygiene() {
- annotatable.visit_with(&mut GateProcMacroInput { parse_sess: self.cx.parse_sess });
+ annotatable
+ .visit_with(&mut GateProcMacroInput { parse_sess: &self.cx.sess.parse_sess });
}
}
..ExpnData::default(
ExpnKind::Macro(MacroKind::Attr, sym::derive),
item.span(),
- self.cx.parse_sess.edition,
+ self.cx.sess.parse_sess.edition,
None,
)
}),
if a.has_name(sym::derive) {
*after_derive = true;
}
- !attr::is_known(a) && !is_builtin_attr(a)
+ !self.cx.sess.is_attr_known(a) && !is_builtin_attr(a)
})
.map(|i| attrs.remove(i));
if let Some(attr) = &attr {
&& !attr.has_name(sym::test)
{
feature_err(
- &self.cx.parse_sess,
+ &self.cx.sess.parse_sess,
sym::custom_inner_attributes,
attr.span,
"non-builtin inner attributes are unstable",
fn check_attributes(&mut self, attrs: &[ast::Attribute]) {
let features = self.cx.ecfg.features.unwrap();
for attr in attrs.iter() {
- rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.parse_sess, features);
- validate_attr::check_meta(self.cx.parse_sess, attr);
+ rustc_ast_passes::feature_gate::check_attribute(attr, self.cx.sess, features);
+ validate_attr::check_meta(&self.cx.sess.parse_sess, attr);
// macros are expanded before any lint passes so this warning has to be hardcoded
if attr.has_name(sym::derive) {
}
if attr.doc_str().is_some() {
- self.cx.parse_sess.buffer_lint_with_diagnostic(
+ self.cx.sess.parse_sess.buffer_lint_with_diagnostic(
&UNUSED_DOC_COMMENTS,
attr.span,
ast::CRATE_NODE_ID,
})
}
ast::ItemKind::Mod(ref mut old_mod @ ast::Mod { .. }) if ident != Ident::invalid() => {
- let sess = self.cx.parse_sess;
+ let sess = &self.cx.sess.parse_sess;
let orig_ownership = self.cx.current_expansion.directory_ownership;
let mut module = (*self.cx.current_expansion.module).clone();
let Directory { ownership, path } = if old_mod.inline {
// Inline `mod foo { ... }`, but we still need to push directories.
item.attrs = attrs;
- push_directory(ident, &item.attrs, dir)
+ push_directory(&self.cx.sess, ident, &item.attrs, dir)
} else {
// We have an outline `mod foo;` so we need to parse the file.
let (new_mod, dir) =
- parse_external_mod(sess, ident, span, dir, &mut attrs, pushed);
+ parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed);
let krate = ast::Crate {
span: new_mod.inner,
fn visit_attribute(&mut self, at: &mut ast::Attribute) {
// turn `#[doc(include="filename")]` attributes into `#[doc(include(file="filename",
// contents="file contents")]` attributes
- if !at.check_name(sym::doc) {
+ if !self.cx.sess.check_name(at, sym::doc) {
return noop_visit_attribute(at, self);
}
}
if let Some(file) = it.value_str() {
- let err_count = self.cx.parse_sess.span_diagnostic.err_count();
+ let err_count = self.cx.sess.parse_sess.span_diagnostic.err_count();
self.check_attributes(slice::from_ref(at));
- if self.cx.parse_sess.span_diagnostic.err_count() > err_count {
+ if self.cx.sess.parse_sess.span_diagnostic.err_count() > err_count {
// avoid loading the file if they haven't enabled the feature
return noop_visit_attribute(at, self);
}
use rustc_feature::Features;
use rustc_parse::parser::Parser;
use rustc_session::parse::ParseSess;
+use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::hygiene::Transparency;
use rustc_span::symbol::{kw, sym, Ident, MacroRulesNormalizedIdent};
lhses: &[mbe::TokenTree],
rhses: &[mbe::TokenTree],
) -> Box<dyn MacResult + 'cx> {
- let sess = cx.parse_sess;
+ let sess = &cx.sess.parse_sess;
if cx.trace_macros() {
let msg = format!("expanding `{}! {{ {} }}`", name, pprust::tts_to_string(&arg));
/// Converts a macro item into a syntax extension.
pub fn compile_declarative_macro(
- sess: &ParseSess,
+ sess: &Session,
features: &Features,
def: &ast::Item,
edition: Edition,
)
};
- let diag = &sess.span_diagnostic;
+ let diag = &sess.parse_sess.span_diagnostic;
let lhs_nm = Ident::new(sym::lhs, def.span);
let rhs_nm = Ident::new(sym::rhs, def.span);
let tt_spec = Some(NonterminalKind::TT);
),
];
- let parser = Parser::new(sess, body, true, rustc_parse::MACRO_ARGUMENTS);
+ let parser = Parser::new(&sess.parse_sess, body, true, rustc_parse::MACRO_ARGUMENTS);
let argument_map = match parse_tt(&mut Cow::Borrowed(&parser), &argument_gram) {
Success(m) => m,
Failure(token, msg) => {
let s = parse_failure_msg(&token);
let sp = token.span.substitute_dummy(def.span);
- sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit();
+ sess.parse_sess.span_diagnostic.struct_span_err(sp, &s).span_label(sp, msg).emit();
return mk_syn_ext(Box::new(macro_rules_dummy_expander));
}
Error(sp, msg) => {
- sess.span_diagnostic.struct_span_err(sp.substitute_dummy(def.span), &msg).emit();
+ sess.parse_sess
+ .span_diagnostic
+ .struct_span_err(sp.substitute_dummy(def.span), &msg)
+ .emit();
return mk_syn_ext(Box::new(macro_rules_dummy_expander));
}
ErrorReported => {
.map(|m| {
if let MatchedNonterminal(ref nt) = *m {
if let NtTT(ref tt) = **nt {
- let tt = mbe::quoted::parse(tt.clone().into(), true, sess, def.id)
- .pop()
- .unwrap();
- valid &= check_lhs_nt_follows(sess, features, &def.attrs, &tt);
+ let tt =
+ mbe::quoted::parse(tt.clone().into(), true, &sess.parse_sess, def.id)
+ .pop()
+ .unwrap();
+ valid &= check_lhs_nt_follows(&sess.parse_sess, features, &def.attrs, &tt);
return tt;
}
}
- sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
+ sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
})
.collect::<Vec<mbe::TokenTree>>(),
- _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
+ _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
};
let rhses = match argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] {
.map(|m| {
if let MatchedNonterminal(ref nt) = *m {
if let NtTT(ref tt) = **nt {
- return mbe::quoted::parse(tt.clone().into(), false, sess, def.id)
- .pop()
- .unwrap();
+ return mbe::quoted::parse(
+ tt.clone().into(),
+ false,
+ &sess.parse_sess,
+ def.id,
+ )
+ .pop()
+ .unwrap();
}
}
- sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
+ sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
})
.collect::<Vec<mbe::TokenTree>>(),
- _ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
+ _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
};
for rhs in &rhses {
- valid &= check_rhs(sess, rhs);
+ valid &= check_rhs(&sess.parse_sess, rhs);
}
// don't abort iteration early, so that errors for multiple lhses can be reported
for lhs in &lhses {
- valid &= check_lhs_no_empty_seq(sess, slice::from_ref(lhs));
+ valid &= check_lhs_no_empty_seq(&sess.parse_sess, slice::from_ref(lhs));
}
- valid &= macro_check::check_meta_variables(sess, def.id, def.span, &lhses, &rhses);
+ valid &= macro_check::check_meta_variables(&sess.parse_sess, def.id, def.span, &lhses, &rhses);
- let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
+ let (transparency, transparency_error) = attr::find_transparency(sess, &def.attrs, macro_rules);
match transparency_error {
Some(TransparencyError::UnknownTransparency(value, span)) => {
diag.span_err(span, &format!("unknown macro transparency: `{}`", value))
use rustc_ast::ast::{Attribute, Mod};
-use rustc_ast::{attr, token};
+use rustc_ast::token;
use rustc_errors::{struct_span_err, PResult};
use rustc_parse::new_parser_from_file;
use rustc_session::parse::ParseSess;
+use rustc_session::Session;
use rustc_span::source_map::{FileName, Span};
use rustc_span::symbol::{sym, Ident};
}
crate fn parse_external_mod(
- sess: &ParseSess,
+ sess: &Session,
id: Ident,
span: Span, // The span to blame on errors.
Directory { mut ownership, path }: Directory,
ownership = mp.ownership;
// Ensure file paths are acyclic.
- let mut included_mod_stack = sess.included_mod_stack.borrow_mut();
- error_on_circular_module(sess, span, &mp.path, &included_mod_stack)?;
+ let mut included_mod_stack = sess.parse_sess.included_mod_stack.borrow_mut();
+ error_on_circular_module(&sess.parse_sess, span, &mp.path, &included_mod_stack)?;
included_mod_stack.push(mp.path.clone());
*pop_mod_stack = true; // We have pushed, so notify caller.
drop(included_mod_stack);
// Actually parse the external file as a module.
- let mut module = new_parser_from_file(sess, &mp.path, Some(span)).parse_mod(&token::Eof)?;
+ let mut module =
+ new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)).parse_mod(&token::Eof)?;
module.0.inline = false;
module
};
}
crate fn push_directory(
+ sess: &Session,
id: Ident,
attrs: &[Attribute],
Directory { mut ownership, mut path }: Directory,
) -> Directory {
- if let Some(filename) = attr::first_attr_value_str_by_name(attrs, sym::path) {
+ if let Some(filename) = sess.first_attr_value_str_by_name(attrs, sym::path) {
path.push(&*filename.as_str());
ownership = DirectoryOwnership::Owned { relative: None };
} else {
}
fn submod_path<'a>(
- sess: &'a ParseSess,
+ sess: &'a Session,
id: Ident,
span: Span,
attrs: &[Attribute],
ownership: DirectoryOwnership,
dir_path: &Path,
) -> PResult<'a, ModulePathSuccess> {
- if let Some(path) = submod_path_from_attr(attrs, dir_path) {
+ if let Some(path) = submod_path_from_attr(sess, attrs, dir_path) {
let ownership = match path.file_name().and_then(|s| s.to_str()) {
// All `#[path]` files are treated as though they are a `mod.rs` file.
// This means that `mod foo;` declarations inside `#[path]`-included
DirectoryOwnership::UnownedViaBlock | DirectoryOwnership::UnownedViaMod => None,
};
let ModulePath { path_exists, name, result } =
- default_submod_path(sess, id, span, relative, dir_path);
+ default_submod_path(&sess.parse_sess, id, span, relative, dir_path);
match ownership {
DirectoryOwnership::Owned { .. } => Ok(result?),
DirectoryOwnership::UnownedViaBlock => {
let _ = result.map_err(|mut err| err.cancel());
- error_decl_mod_in_block(sess, span, path_exists, &name)
+ error_decl_mod_in_block(&sess.parse_sess, span, path_exists, &name)
}
DirectoryOwnership::UnownedViaMod => {
let _ = result.map_err(|mut err| err.cancel());
- error_cannot_declare_mod_here(sess, span, path_exists, &name)
+ error_cannot_declare_mod_here(&sess.parse_sess, span, path_exists, &name)
}
}
}
/// Derive a submodule path from the first found `#[path = "path_string"]`.
/// The provided `dir_path` is joined with the `path_string`.
// Public for rustfmt usage.
-pub fn submod_path_from_attr(attrs: &[Attribute], dir_path: &Path) -> Option<PathBuf> {
+pub fn submod_path_from_attr(
+ sess: &Session,
+ attrs: &[Attribute],
+ dir_path: &Path,
+) -> Option<PathBuf> {
// Extract path string from first `#[path = "path_string"]` attribute.
- let path_string = attr::first_attr_value_str_by_name(attrs, sym::path)?;
+ let path_string = sess.first_attr_value_str_by_name(attrs, sym::path)?;
let path_string = path_string.as_str();
// On windows, the base path might have the form
use rustc_ast::ast;
use rustc_ast::mut_visit::{self, MutVisitor};
-use rustc_ast::with_default_session_globals;
use rustc_ast_pretty::pprust;
use rustc_span::symbol::Ident;
+use rustc_span::with_default_session_globals;
// This version doesn't care about getting comments or doc-strings in.
fn fake_print_crate(s: &mut pprust::State<'_>, krate: &ast::Crate) {
-use rustc_ast::token::{self, Token, TokenKind};
-use rustc_ast::util::comments::is_doc_comment;
-use rustc_ast::with_default_session_globals;
+use rustc_ast::ast::AttrStyle;
+use rustc_ast::token::{self, CommentKind, Token, TokenKind};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{emitter::EmitterWriter, Handler};
use rustc_parse::lexer::StringReader;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{FilePathMapping, SourceMap};
use rustc_span::symbol::Symbol;
+use rustc_span::with_default_session_globals;
use rustc_span::{BytePos, Span};
use std::io;
})
}
-#[test]
-fn line_doc_comments() {
- assert!(is_doc_comment("///"));
- assert!(is_doc_comment("/// blah"));
- assert!(!is_doc_comment("////"));
-}
-
#[test]
fn nested_block_comments() {
with_default_session_globals(|| {
assert_eq!(comment.kind, token::Comment);
assert_eq!((comment.span.lo(), comment.span.hi()), (BytePos(0), BytePos(7)));
assert_eq!(lexer.next_token(), token::Whitespace);
- assert_eq!(lexer.next_token(), token::DocComment(Symbol::intern("/// test")));
+ assert_eq!(
+ lexer.next_token(),
+ token::DocComment(CommentKind::Line, AttrStyle::Outer, Symbol::intern(" test"))
+ );
})
}
use rustc_ast::token::{self, Token};
use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree};
use rustc_ast::visit;
-use rustc_ast::with_default_session_globals;
use rustc_ast_pretty::pprust::item_to_string;
use rustc_errors::PResult;
use rustc_parse::new_parser_from_source_str;
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::with_default_session_globals;
use rustc_span::{BytePos, FileName, Pos, Span};
use std::path::PathBuf;
let source = "/// doc comment\r\nfn foo() {}".to_string();
let item = parse_item_from_source_str(name_1, source, &sess).unwrap().unwrap();
let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap();
- assert_eq!(doc.as_str(), "/// doc comment");
+ assert_eq!(doc.as_str(), " doc comment");
let name_2 = FileName::Custom("crlf_source_2".to_string());
let source = "/// doc comment\r\n/// line 2\r\nfn foo() {}".to_string();
let item = parse_item_from_source_str(name_2, source, &sess).unwrap().unwrap();
let docs = item.attrs.iter().filter_map(|at| at.doc_str()).collect::<Vec<_>>();
- let b: &[_] = &[Symbol::intern("/// doc comment"), Symbol::intern("/// line 2")];
+ let b: &[_] = &[Symbol::intern(" doc comment"), Symbol::intern(" line 2")];
assert_eq!(&docs[..], b);
let name_3 = FileName::Custom("clrf_source_3".to_string());
let source = "/** doc comment\r\n * with CRLF */\r\nfn foo() {}".to_string();
let item = parse_item_from_source_str(name_3, source, &sess).unwrap().unwrap();
let doc = item.attrs.iter().filter_map(|at| at.doc_str()).next().unwrap();
- assert_eq!(doc.as_str(), "/** doc comment\n * with CRLF */");
+ assert_eq!(doc.as_str(), " doc comment\n * with CRLF ");
});
}
let input = if item.pretty_printing_compatibility_hack() {
TokenTree::token(token::Interpolated(Lrc::new(item)), DUMMY_SP).into()
} else {
- nt_to_tokenstream(&item, ecx.parse_sess, DUMMY_SP)
+ nt_to_tokenstream(&item, &ecx.sess.parse_sess, DUMMY_SP)
};
let server = proc_macro_server::Rustc::new(ecx);
}
};
- let error_count_before = ecx.parse_sess.span_diagnostic.err_count();
+ let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count();
let mut parser =
- rustc_parse::stream_to_parser(ecx.parse_sess, stream, Some("proc-macro derive"));
+ rustc_parse::stream_to_parser(&ecx.sess.parse_sess, stream, Some("proc-macro derive"));
let mut items = vec![];
loop {
}
// fail if there have been errors emitted
- if ecx.parse_sess.span_diagnostic.err_count() > error_count_before {
+ if ecx.sess.parse_sess.span_diagnostic.err_count() > error_count_before {
ecx.struct_span_err(span, "proc-macro derive produced unparseable tokens").emit();
}
use rustc_ast::ast;
use rustc_ast::token;
use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint};
-use rustc_ast::util::comments;
use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
use rustc_errors::Diagnostic;
tt!(Punct::new('\'', true))
}
Literal(lit) => tt!(Literal { lit }),
- DocComment(c) => {
- let style = comments::doc_comment_style(c);
- let stripped = comments::strip_doc_comment_decoration(c);
+ DocComment(_, attr_style, data) => {
let mut escaped = String::new();
- for ch in stripped.chars() {
+ for ch in data.as_str().chars() {
escaped.extend(ch.escape_debug());
}
let stream = vec![
span: DelimSpan::from_single(span),
flatten: false,
}));
- if style == ast::AttrStyle::Inner {
+ if attr_style == ast::AttrStyle::Inner {
stack.push(tt!(Punct::new('!', false)));
}
tt!(Punct::new('#', false))
pub fn new(cx: &'a ExtCtxt<'_>) -> Self {
let expn_data = cx.current_expansion.id.expn_data();
Rustc {
- sess: cx.parse_sess,
+ sess: &cx.sess.parse_sess,
def_site: cx.with_def_site_ctxt(expn_data.def_site),
call_site: cx.with_call_site_ctxt(expn_data.call_site),
mixed_site: cx.with_mixed_site_ctxt(expn_data.call_site),
use rustc_ast::ast;
use rustc_ast::tokenstream::TokenStream;
-use rustc_ast::with_default_session_globals;
use rustc_parse::{new_parser_from_source_str, parser::Parser, source_file_to_stream};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::{FilePathMapping, SourceMap};
+use rustc_span::with_default_session_globals;
use rustc_span::{BytePos, MultiSpan, Span};
use rustc_data_structures::sync::Lrc;
use rustc_ast::token;
use rustc_ast::tokenstream::{TokenStream, TokenStreamBuilder, TokenTree};
-use rustc_ast::with_default_session_globals;
+use rustc_span::with_default_session_globals;
use rustc_span::{BytePos, Span, Symbol};
use smallvec::smallvec;
/// Lazily evaluate constants. This allows constants to depend on type parameters.
(active, lazy_normalization_consts, "1.46.0", Some(72219), None),
- /// Alloc calling `transmute` in const fn
+ /// Allows calling `transmute` in const fn
(active, const_fn_transmute, "1.46.0", Some(53605), None),
+ /// The smallest useful subset of `const_generics`.
+ (active, min_const_generics, "1.47.0", Some(74878), None),
+
// -------------------------------------------------------------------------
// feature-group-end: actual feature gates
// -------------------------------------------------------------------------
}
}
- pub fn matches_ns(&self, ns: Namespace) -> bool {
+ pub fn ns(&self) -> Option<Namespace> {
match self {
DefKind::Mod
| DefKind::Struct
| DefKind::ForeignTy
| DefKind::TraitAlias
| DefKind::AssocTy
- | DefKind::TyParam => ns == Namespace::TypeNS,
+ | DefKind::TyParam => Some(Namespace::TypeNS),
DefKind::Fn
| DefKind::Const
| DefKind::Static
| DefKind::Ctor(..)
| DefKind::AssocFn
- | DefKind::AssocConst => ns == Namespace::ValueNS,
+ | DefKind::AssocConst => Some(Namespace::ValueNS),
- DefKind::Macro(..) => ns == Namespace::MacroNS,
+ DefKind::Macro(..) => Some(Namespace::MacroNS),
// Not namespaced.
DefKind::AnonConst
| DefKind::Use
| DefKind::ForeignMod
| DefKind::GlobalAsm
- | DefKind::Impl => false,
+ | DefKind::Impl => None,
}
}
}
pub fn matches_ns(&self, ns: Namespace) -> bool {
match self {
- Res::Def(kind, ..) => kind.matches_ns(ns),
+ Res::Def(kind, ..) => kind.ns() == Some(ns),
Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => ns == Namespace::TypeNS,
Res::SelfCtor(..) | Res::Local(..) => ns == Namespace::ValueNS,
Res::NonMacroAttr(..) => ns == Namespace::MacroNS,
/// Extracts the first `lang = "$name"` out of a list of attributes.
/// The attributes `#[panic_handler]` and `#[alloc_error_handler]`
/// are also extracted out when found.
-pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
+///
+/// About the `check_name` argument: passing in a `Session` would be simpler,
+/// because then we could call `Session::check_name` directly. But we want to
+/// avoid the need for `librustc_hir` to depend on `librustc_session`, so we
+/// use a closure instead.
+pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Symbol, Span)>
+where
+ F: Fn(&'a ast::Attribute, Symbol) -> bool,
+{
attrs.iter().find_map(|attr| {
Some(match attr {
- _ if attr.check_name(sym::lang) => (attr.value_str()?, attr.span),
- _ if attr.check_name(sym::panic_handler) => (sym::panic_impl, attr.span),
- _ if attr.check_name(sym::alloc_error_handler) => (sym::oom, attr.span),
+ _ if check_name(attr, sym::lang) => (attr.value_str()?, attr.span),
+ _ if check_name(attr, sym::panic_handler) => (sym::panic_impl, attr.span),
+ _ if check_name(attr, sym::alloc_error_handler) => (sym::oom, attr.span),
_ => return None,
})
})
};
}
-pub fn link_name(attrs: &[ast::Attribute]) -> Option<Symbol> {
- lang_items::extract(attrs).and_then(|(name, _)| {
+/// The `check_name` argument avoids the need for `librustc_hir` to depend on
+/// `librustc_session`.
+pub fn link_name<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<Symbol>
+where
+ F: Fn(&'a ast::Attribute, Symbol) -> bool
+{
+ lang_items::extract(check_name, attrs).and_then(|(name, _)| {
$(if name == sym::$name {
Some(sym::$sym)
} else)* {
let def_id = self.tcx.hir().local_def_id(hir_id);
let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id());
for attr in attrs {
- if attr.check_name(sym::rustc_if_this_changed) {
+ if self.tcx.sess.check_name(attr, sym::rustc_if_this_changed) {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
None => DepNode::from_def_path_hash(def_path_hash, DepKind::hir_owner),
},
};
self.if_this_changed.push((attr.span, def_id.to_def_id(), dep_node));
- } else if attr.check_name(sym::rustc_then_this_would_need) {
+ } else if self.tcx.sess.check_name(attr, sym::rustc_then_this_would_need) {
let dep_node_interned = self.argument(attr);
let dep_node = match dep_node_interned {
Some(n) => match DepNode::from_label_string(&n.as_str(), def_path_hash) {
.collect_and_partition_mono_items(LOCAL_CRATE)
.1
.iter()
- .map(|cgu| cgu.name())
- .collect::<BTreeSet<Symbol>>();
+ .map(|cgu| cgu.name().to_string())
+ .collect::<BTreeSet<String>>();
let ams = AssertModuleSource { tcx, available_cgus };
struct AssertModuleSource<'tcx> {
tcx: TyCtxt<'tcx>,
- available_cgus: BTreeSet<Symbol>,
+ available_cgus: BTreeSet<String>,
}
impl AssertModuleSource<'tcx> {
fn check_attr(&self, attr: &ast::Attribute) {
- let (expected_reuse, comp_kind) = if attr.check_name(sym::rustc_partition_reused) {
- (CguReuse::PreLto, ComparisonKind::AtLeast)
- } else if attr.check_name(sym::rustc_partition_codegened) {
- (CguReuse::No, ComparisonKind::Exact)
- } else if attr.check_name(sym::rustc_expected_cgu_reuse) {
- match self.field(attr, sym::kind) {
- sym::no => (CguReuse::No, ComparisonKind::Exact),
- sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
- sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
- sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
- other => {
- self.tcx.sess.span_fatal(
- attr.span,
- &format!("unknown cgu-reuse-kind `{}` specified", other),
- );
+ let (expected_reuse, comp_kind) =
+ if self.tcx.sess.check_name(attr, sym::rustc_partition_reused) {
+ (CguReuse::PreLto, ComparisonKind::AtLeast)
+ } else if self.tcx.sess.check_name(attr, sym::rustc_partition_codegened) {
+ (CguReuse::No, ComparisonKind::Exact)
+ } else if self.tcx.sess.check_name(attr, sym::rustc_expected_cgu_reuse) {
+ match self.field(attr, sym::kind) {
+ sym::no => (CguReuse::No, ComparisonKind::Exact),
+ sym::pre_dash_lto => (CguReuse::PreLto, ComparisonKind::Exact),
+ sym::post_dash_lto => (CguReuse::PostLto, ComparisonKind::Exact),
+ sym::any => (CguReuse::PreLto, ComparisonKind::AtLeast),
+ other => {
+ self.tcx.sess.span_fatal(
+ attr.span,
+ &format!("unknown cgu-reuse-kind `{}` specified", other),
+ );
+ }
}
- }
- } else {
- return;
- };
+ } else {
+ return;
+ };
if !self.tcx.sess.opts.debugging_opts.query_dep_graph {
self.tcx.sess.span_fatal(
debug!("mapping '{}' to cgu name '{}'", self.field(attr, sym::module), cgu_name);
- if !self.available_cgus.contains(&cgu_name) {
+ if !self.available_cgus.contains(&*cgu_name.as_str()) {
self.tcx.sess.span_err(
attr.span,
&format!(
- "no module named `{}` (mangled: {}). \
- Available modules: {}",
+ "no module named `{}` (mangled: {}). Available modules: {}",
user_path,
cgu_name,
self.available_cgus
impl DirtyCleanVisitor<'tcx> {
/// Possibly "deserialize" the attribute into a clean/dirty assertion
fn assertion_maybe(&mut self, item_id: hir::HirId, attr: &Attribute) -> Option<Assertion> {
- let is_clean = if attr.check_name(sym::rustc_dirty) {
+ let is_clean = if self.tcx.sess.check_name(attr, sym::rustc_dirty) {
false
- } else if attr.check_name(sym::rustc_clean) {
+ } else if self.tcx.sess.check_name(attr, sym::rustc_clean) {
true
} else {
// skip: not rustc_clean/dirty
impl FindAllAttrs<'tcx> {
fn is_active_attr(&mut self, attr: &Attribute) -> bool {
for attr_name in &self.attr_names {
- if attr.check_name(*attr_name) && check_config(self.tcx, attr) {
+ if self.tcx.sess.check_name(attr, *attr_name) && check_config(self.tcx, attr) {
return true;
}
}
debug!("try_report_named_anon_conflict: ret ty {:?}", ty);
if sub == &ty::ReStatic
- && v.0
- .into_iter()
- .filter(|t| t.span.desugaring_kind().is_none())
- .next()
- .is_some()
+ && v.0.into_iter().find(|t| t.span.desugaring_kind().is_none()).is_some()
{
// If the failure is due to a `'static` requirement coming from a `dyn` or
// `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case
param.param_ty.to_string(),
Applicability::MaybeIncorrect,
);
- } else if let Some(_) = opaque
+ } else if opaque
.bounds
.iter()
.filter_map(|arg| match arg {
_ => None,
})
.next()
+ .is_some()
{
} else {
err.span_suggestion_verbose(
ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
ty::Covariant => self.relate(a, b),
// FIXME(#41044) -- not correct, need test
- ty::Bivariant => Ok(a.clone()),
+ ty::Bivariant => Ok(a),
ty::Contravariant => self.fields.lub(self.a_is_expected).relate(a, b),
}
}
// very challenging, switch to invariance. This is obviously
// overly conservative but works ok in practice.
self.relate_with_variance(ty::Variance::Invariant, a, b)?;
- Ok(a.clone())
+ Ok(a)
}
}
self.a_scopes.pop().unwrap();
}
- Ok(a.clone())
+ Ok(a)
}
}
) -> TypeError<'tcx> {
debug!("error: placeholder={:?}, other_region={:?}", placeholder, other_region);
if self.overly_polymorphic {
- return TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region);
+ TypeError::RegionsOverlyPolymorphic(placeholder.name, other_region)
} else {
- return TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region);
+ TypeError::RegionsInsufficientlyPolymorphic(placeholder.name, other_region)
}
}
}
match variance {
ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b),
ty::Covariant => self.relate(a, b),
- ty::Bivariant => Ok(a.clone()),
+ ty::Bivariant => Ok(a),
ty::Contravariant => self.with_expected_switched(|this| this.relate(b, a)),
}
}
/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
- rustc_ast::with_default_session_globals(move || {
+ rustc_span::with_default_session_globals(move || {
let cfg = cfgspecs
.into_iter()
.map(|s| {
)
});
- let (krate, features) = rustc_expand::config::features(
- krate,
- &sess.parse_sess,
- sess.edition(),
- &sess.opts.debugging_opts.allow_features,
- );
+ let (krate, features) = rustc_expand::config::features(sess, krate);
// these need to be set "early" so that expansion sees `quote` if enabled.
sess.init_features(features);
let (krate, name) = rustc_builtin_macros::standard_library_imports::inject(
krate,
&mut resolver,
- &sess.parse_sess,
+ &sess,
alt_std_name,
);
if let Some(name) = name {
krate
});
- util::check_attr_crate_type(&krate.attrs, &mut resolver.lint_buffer());
+ util::check_attr_crate_type(&sess, &krate.attrs, &mut resolver.lint_buffer());
// Expand all macros
krate = sess.time("macro_expand_crate", || {
};
let extern_mod_loaded = |k: &ast::Crate| pre_expansion_lint(sess, lint_store, k);
- let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver, Some(&extern_mod_loaded));
+ let mut ecx = ExtCtxt::new(&sess, cfg, &mut resolver, Some(&extern_mod_loaded));
// Expand macros now!
let krate = sess.time("expand_crate", || ecx.monotonic_expander().expand_crate(krate));
});
let mut missing_fragment_specifiers: Vec<_> = ecx
+ .sess
.parse_sess
.missing_fragment_specifiers
.borrow()
})?;
sess.time("maybe_building_test_harness", || {
- rustc_builtin_macros::test_harness::inject(
- &sess.parse_sess,
- &mut resolver,
- sess.opts.test,
- &mut krate,
- sess.diagnostic(),
- &sess.features_untracked(),
- sess.panic_strategy(),
- sess.target.target.options.panic_strategy,
- sess.opts.debugging_opts.panic_abort_tests,
- )
+ rustc_builtin_macros::test_harness::inject(&sess, &mut resolver, &mut krate)
});
if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty {
let num_crate_types = crate_types.len();
let is_test_crate = sess.opts.test;
rustc_builtin_macros::proc_macro_harness::inject(
- &sess.parse_sess,
+ &sess,
&mut resolver,
krate,
is_proc_macro_crate,
// Needs to go *after* expansion to be able to check the results of macro expansion.
sess.time("complete_gated_feature_checking", || {
- rustc_ast_passes::feature_gate::check_crate(
- &krate,
- &sess.parse_sess,
- &sess.features_untracked(),
- sess.opts.unstable_features,
- );
+ rustc_ast_passes::feature_gate::check_crate(&krate, sess);
});
// Add all buffered lints from the `ParseSess` to the `Session`.
-use rustc_ast::attr;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
fn proc_macro_decls_static(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<DefId> {
assert_eq!(cnum, LOCAL_CRATE);
- let mut finder = Finder { decls: None };
+ let mut finder = Finder { tcx, decls: None };
tcx.hir().krate().visit_all_item_likes(&mut finder);
finder.decls.map(|id| tcx.hir().local_def_id(id).to_def_id())
}
-struct Finder {
+struct Finder<'tcx> {
+ tcx: TyCtxt<'tcx>,
decls: Option<hir::HirId>,
}
-impl<'v> ItemLikeVisitor<'v> for Finder {
+impl<'v> ItemLikeVisitor<'v> for Finder<'_> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
- if attr::contains_name(&item.attrs, sym::rustc_proc_macro_decls) {
+ if self.tcx.sess.contains_name(&item.attrs, sym::rustc_proc_macro_decls) {
self.decls = Some(item.hir_id);
}
}
None => {
let parse_result = self.parse()?;
let krate = parse_result.peek();
- find_crate_name(Some(self.session()), &krate.attrs, &self.compiler.input)
+ find_crate_name(self.session(), &krate.attrs, &self.compiler.input)
}
})
})
};
let attrs = &*tcx.get_attrs(def_id.to_def_id());
- let attrs = attrs.iter().filter(|attr| attr.check_name(sym::rustc_error));
+ let attrs = attrs.iter().filter(|attr| tcx.sess.check_name(attr, sym::rustc_error));
for attr in attrs {
match attr.meta_item_list() {
// Check if there is a `#[rustc_error(delay_span_bug_from_inside_query)]`.
// When the user supplies --test we should implicitly supply --cfg test
#[test]
fn test_switch_implies_cfg_test() {
- rustc_ast::with_default_session_globals(|| {
+ rustc_span::with_default_session_globals(|| {
let matches = optgroups().parse(&["--test".to_string()]).unwrap();
let (sess, cfg) = mk_session(matches);
let cfg = build_configuration(&sess, to_crate_config(cfg));
// When the user supplies --test and --cfg test, don't implicitly add another --cfg test
#[test]
fn test_switch_implies_cfg_test_unless_cfg_test() {
- rustc_ast::with_default_session_globals(|| {
+ rustc_span::with_default_session_globals(|| {
let matches = optgroups().parse(&["--test".to_string(), "--cfg=test".to_string()]).unwrap();
let (sess, cfg) = mk_session(matches);
let cfg = build_configuration(&sess, to_crate_config(cfg));
#[test]
fn test_can_print_warnings() {
- rustc_ast::with_default_session_globals(|| {
+ rustc_span::with_default_session_globals(|| {
let matches = optgroups().parse(&["-Awarnings".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
assert!(!sess.diagnostic().can_emit_warnings());
});
- rustc_ast::with_default_session_globals(|| {
+ rustc_span::with_default_session_globals(|| {
let matches =
optgroups().parse(&["-Awarnings".to_string(), "-Dwarnings".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
assert!(sess.diagnostic().can_emit_warnings());
});
- rustc_ast::with_default_session_globals(|| {
+ rustc_span::with_default_session_globals(|| {
let matches = optgroups().parse(&["-Adead_code".to_string()]).unwrap();
let (sess, _) = mk_session(matches);
assert!(sess.diagnostic().can_emit_warnings());
crate::callbacks::setup_callbacks();
let main_handler = move || {
- rustc_ast::with_session_globals(edition, || {
+ rustc_span::with_session_globals(edition, || {
if let Some(stderr) = stderr {
io::set_panic(Some(box Sink(stderr.clone())));
}
let with_pool = move |pool: &rayon::ThreadPool| pool.install(move || f());
- rustc_ast::with_session_globals(edition, || {
- rustc_ast::SESSION_GLOBALS.with(|ast_session_globals| {
- rustc_span::SESSION_GLOBALS.with(|span_session_globals| {
- // The main handler runs for each Rayon worker thread and sets
- // up the thread local rustc uses. ast_session_globals and
- // span_session_globals are captured and set on the new
- // threads. ty::tls::with_thread_locals sets up thread local
- // callbacks from librustc_ast.
- let main_handler = move |thread: rayon::ThreadBuilder| {
- rustc_ast::SESSION_GLOBALS.set(ast_session_globals, || {
- rustc_span::SESSION_GLOBALS.set(span_session_globals, || {
- if let Some(stderr) = stderr {
- io::set_panic(Some(box Sink(stderr.clone())));
- }
- thread.run()
- })
- })
- };
+ rustc_span::with_session_globals(edition, || {
+ rustc_span::SESSION_GLOBALS.with(|session_globals| {
+ // The main handler runs for each Rayon worker thread and sets up
+ // the thread local rustc uses. `session_globals` is captured and set
+ // on the new threads.
+ let main_handler = move |thread: rayon::ThreadBuilder| {
+ rustc_span::SESSION_GLOBALS.set(session_globals, || {
+ if let Some(stderr) = stderr {
+ io::set_panic(Some(box Sink(stderr.clone())));
+ }
+ thread.run()
+ })
+ };
- config.build_scoped(main_handler, with_pool).unwrap()
- })
+ config.build_scoped(main_handler, with_pool).unwrap()
})
})
}
CrateDisambiguator::from(hasher.finish::<Fingerprint>())
}
-pub(crate) fn check_attr_crate_type(attrs: &[ast::Attribute], lint_buffer: &mut LintBuffer) {
+pub(crate) fn check_attr_crate_type(
+ sess: &Session,
+ attrs: &[ast::Attribute],
+ lint_buffer: &mut LintBuffer,
+) {
// Unconditionally collect crate types from attributes to make them used
for a in attrs.iter() {
- if a.check_name(sym::crate_type) {
+ if sess.check_name(a, sym::crate_type) {
if let Some(n) = a.value_str() {
if categorize_crate_type(n).is_some() {
return;
let attr_types: Vec<CrateType> = attrs
.iter()
.filter_map(|a| {
- if a.check_name(sym::crate_type) {
+ if session.check_name(a, sym::crate_type) {
match a.value_str() {
Some(s) => categorize_crate_type(s),
_ => None,
.opts
.crate_name
.clone()
- .or_else(|| rustc_attr::find_crate_name(attrs).map(|n| n.to_string()))
+ .or_else(|| rustc_attr::find_crate_name(&sess, attrs).map(|n| n.to_string()))
.unwrap_or_else(|| input.filestem().to_owned());
OutputFilenames::new(
use rustc_middle::ty::subst::{GenericArgKind, Subst};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::lint::FutureIncompatibleInfo;
+use rustc_session::Session;
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
impl EarlyLintPass for UnsafeCode {
fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) {
- if attr.check_name(sym::allow_internal_unsafe) {
+ if cx.sess().check_name(attr, sym::allow_internal_unsafe) {
self.report_unsafe(cx, attr.span, |lint| {
lint.build(
"`allow_internal_unsafe` allows defining \
impl_lint_pass!(MissingDoc => [MISSING_DOCS]);
-fn has_doc(attr: &ast::Attribute) -> bool {
+fn has_doc(sess: &Session, attr: &ast::Attribute) -> bool {
if attr.is_doc_comment() {
return true;
}
- if !attr.check_name(sym::doc) {
+ if !sess.check_name(attr, sym::doc) {
return false;
}
}
}
- let has_doc = attrs.iter().any(|a| has_doc(a));
+ let has_doc = attrs.iter().any(|a| has_doc(cx.sess(), a));
if !has_doc {
cx.struct_span_lint(
MISSING_DOCS,
}
impl<'tcx> LateLintPass<'tcx> for MissingDoc {
- fn enter_lint_attrs(&mut self, _: &LateContext<'_>, attrs: &[ast::Attribute]) {
+ fn enter_lint_attrs(&mut self, cx: &LateContext<'_>, attrs: &[ast::Attribute]) {
let doc_hidden = self.doc_hidden()
|| attrs.iter().any(|attr| {
- attr.check_name(sym::doc)
+ cx.sess().check_name(attr, sym::doc)
&& match attr.meta_item_list() {
None => false,
Some(l) => attr::list_contains_name(&l, sym::hidden),
self.check_missing_docs_attrs(cx, None, &krate.item.attrs, krate.item.span, "the", "crate");
for macro_def in krate.exported_macros {
- let has_doc = macro_def.attrs.iter().any(|a| has_doc(a));
+ let has_doc = macro_def.attrs.iter().any(|a| has_doc(cx.sess(), a));
if !has_doc {
cx.struct_span_lint(
MISSING_DOCS,
return;
}
}
- if attr.check_name(sym::no_start) || attr.check_name(sym::crate_id) {
+ if cx.sess().check_name(attr, sym::no_start) || cx.sess().check_name(attr, sym::crate_id) {
let path_str = pprust::path_to_string(&attr.get_normal_item().path);
let msg = format!("use of deprecated attribute `{}`: no longer used.", path_str);
lint_deprecated_attr(cx, attr, &msg, None);
let span = sugared_span.take().unwrap_or_else(|| attr.span);
- if attr.is_doc_comment() || attr.check_name(sym::doc) {
+ if attr.is_doc_comment() || cx.sess().check_name(attr, sym::doc) {
cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| {
let mut err = lint.build("unused doc comment");
err.span_label(
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
match it.kind {
hir::ItemKind::Fn(.., ref generics, _) => {
- if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, sym::no_mangle) {
+ if let Some(no_mangle_attr) = cx.sess().find_by_name(&it.attrs, sym::no_mangle) {
for param in generics.params {
match param.kind {
GenericParamKind::Lifetime { .. } => {}
}
}
hir::ItemKind::Const(..) => {
- if attr::contains_name(&it.attrs, sym::no_mangle) {
+ if cx.sess().contains_name(&it.attrs, sym::no_mangle) {
// Const items do not refer to a particular location in memory, and therefore
// don't have anything to attach a symbol to
cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, |lint| {
);
impl<'tcx> LateLintPass<'tcx> for UnstableFeatures {
- fn check_attribute(&mut self, ctx: &LateContext<'_>, attr: &ast::Attribute) {
- if attr.check_name(sym::feature) {
+ fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) {
+ if cx.sess().check_name(attr, sym::feature) {
if let Some(items) = attr.meta_item_list() {
for item in items {
- ctx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
+ cx.struct_span_lint(UNSTABLE_FEATURES, item.span(), |lint| {
lint.build("unstable feature").emit()
});
}
return;
}
- if let Some(attr) = attr::find_by_name(&it.attrs, sym::rustc_test_marker) {
+ if let Some(attr) = cx.sess().find_by_name(&it.attrs, sym::rustc_test_marker) {
cx.struct_span_lint(UNNAMEABLE_TEST_ITEMS, attr.span, |lint| {
lint.build("cannot test inner items").emit()
});
overridden_link_name,
tcx.get_attrs(did.to_def_id())
.iter()
- .find(|at| at.check_name(sym::link_name))
+ .find(|at| tcx.sess.check_name(at, sym::link_name))
.unwrap()
.span,
)
};
let meta = unwrap_or!(attr.meta(), continue);
- attr::mark_used(attr);
+ self.sess.mark_attr_used(attr);
let mut metas = unwrap_or!(meta.meta_item_list(), continue);
let has_repr_c = it
.attrs
.iter()
- .any(|attr| attr::find_repr_attrs(&cx.sess.parse_sess, attr).contains(&attr::ReprC));
+ .any(|attr| attr::find_repr_attrs(&cx.sess, attr).contains(&attr::ReprC));
if has_repr_c {
return;
let crate_ident = if let Some(name) = &cx.tcx.sess.opts.crate_name {
Some(Ident::from_str(name))
} else {
- attr::find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
+ cx.sess()
+ .find_by_name(&cx.tcx.hir().attrs(hir::CRATE_HIR_ID), sym::crate_name)
.and_then(|attr| attr.meta())
.and_then(|meta| {
meta.name_value_literal().and_then(|lit| {
},
FnKind::ItemFn(ident, _, header, _, attrs) => {
// Skip foreign-ABI #[no_mangle] functions (Issue #31924)
- if header.abi != Abi::Rust && attr::contains_name(attrs, sym::no_mangle) {
+ if header.abi != Abi::Rust && cx.sess().contains_name(attrs, sym::no_mangle) {
return;
}
self.check_snake_case(cx, "function", ident);
impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
match it.kind {
- hir::ItemKind::Static(..) if !attr::contains_name(&it.attrs, sym::no_mangle) => {
+ hir::ItemKind::Static(..) if !cx.sess().contains_name(&it.attrs, sym::no_mangle) => {
NonUpperCaseGlobals::check_upper_case(cx, "static variable", &it.ident);
}
hir::ItemKind::Const(..) => {
let guaranteed_nonnull_optimization = tcx
.get_attrs(def.did)
.iter()
- .any(|a| a.check_name(sym::rustc_nonnull_optimization_guaranteed));
+ .any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed));
if guaranteed_nonnull_optimization {
return true;
_ => false,
}
}
+
/// Given a non-null scalar (or transparent) type `ty`, return the nullable version of that type.
/// If the type passed in was not scalar, returns None.
fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
}
// If `ty` is a `repr(transparent)` newtype, and the non-zero-sized type is a generic
// argument, which after substitution, is `()`, then this branch can be hit.
- FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => return,
+ FfiResult::FfiUnsafe { ty, .. } if is_return_type && ty.is_unit() => {}
FfiResult::FfiUnsafe { ty, reason, help } => {
self.emit_ffi_unsafe_type_lint(ty, sp, &reason, help.as_deref());
}
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast::ast;
use rustc_ast::ast::{ExprKind, StmtKind};
-use rustc_ast::attr;
use rustc_ast::util::parser;
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashMap;
descr_post_path: &str,
) -> bool {
for attr in cx.tcx.get_attrs(def_id).iter() {
- if attr.check_name(sym::must_use) {
+ if cx.sess().check_name(attr, sym::must_use) {
cx.struct_span_lint(UNUSED_MUST_USE, span, |lint| {
let msg = format!(
"unused {}`{}`{} that must be used",
}
}
- if !attr::is_used(attr) {
+ if !cx.sess().is_attr_used(attr) {
debug!("emitting warning for: {:?}", attr);
cx.struct_span_lint(UNUSED_ATTRIBUTES, attr.span, |lint| {
lint.build("unused attribute").emit()
use crate::locator::{CrateError, CrateLocator, CratePaths};
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
-use rustc_ast::expand::allocator::{global_allocator_spans, AllocatorKind};
-use rustc_ast::{ast, attr};
+use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_ast::{ast, visit};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::Lrc;
// compilation mode also comes into play.
let desired_strategy = self.sess.panic_strategy();
let mut runtime_found = false;
- let mut needs_panic_runtime = attr::contains_name(&krate.attrs, sym::needs_panic_runtime);
+ let mut needs_panic_runtime =
+ self.sess.contains_name(&krate.attrs, sym::needs_panic_runtime);
self.cstore.iter_crate_data(|cnum, data| {
needs_panic_runtime = needs_panic_runtime || data.needs_panic_runtime();
}
fn inject_allocator_crate(&mut self, krate: &ast::Crate) {
- self.cstore.has_global_allocator = match &*global_allocator_spans(krate) {
+ self.cstore.has_global_allocator = match &*global_allocator_spans(&self.sess, krate) {
[span1, span2, ..] => {
self.sess
.struct_span_err(*span2, "cannot define multiple global allocators")
// Check to see if we actually need an allocator. This desire comes
// about through the `#![needs_allocator]` attribute and is typically
// written down in liballoc.
- let mut needs_allocator = attr::contains_name(&krate.attrs, sym::needs_allocator);
+ let mut needs_allocator = self.sess.contains_name(&krate.attrs, sym::needs_allocator);
self.cstore.iter_crate_data(|_, data| {
needs_allocator = needs_allocator || data.needs_allocator();
});
// allocator. At this point our allocator request is typically fulfilled
// by the standard library, denoted by the `#![default_lib_allocator]`
// attribute.
- let mut has_default = attr::contains_name(&krate.attrs, sym::default_lib_allocator);
+ let mut has_default = self.sess.contains_name(&krate.attrs, sym::default_lib_allocator);
self.cstore.iter_crate_data(|_, data| {
if data.has_default_lib_allocator() {
has_default = true;
);
let name = match orig_name {
Some(orig_name) => {
- validate_crate_name(Some(self.sess), &orig_name.as_str(), Some(item.span));
+ validate_crate_name(self.sess, &orig_name.as_str(), Some(item.span));
orig_name
}
None => item.ident.name,
};
- let dep_kind = if attr::contains_name(&item.attrs, sym::no_link) {
+ let dep_kind = if self.sess.contains_name(&item.attrs, sym::no_link) {
CrateDepKind::MacrosOnly
} else {
CrateDepKind::Explicit
self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok()
}
}
+
+fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec<Span> {
+ struct Finder<'a> {
+ sess: &'a Session,
+ name: Symbol,
+ spans: Vec<Span>,
+ }
+ impl<'ast, 'a> visit::Visitor<'ast> for Finder<'a> {
+ fn visit_item(&mut self, item: &'ast ast::Item) {
+ if item.ident.name == self.name
+ && self.sess.contains_name(&item.attrs, sym::rustc_std_internal_symbol)
+ {
+ self.spans.push(item.span);
+ }
+ visit::walk_item(self, item)
+ }
+ }
+
+ let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc));
+ let mut f = Finder { sess, name, spans: Vec::new() };
+ visit::walk_crate(&mut f, krate);
+ f.spans
+}
use rustc_target::spec::abi::Abi;
crate fn collect(tcx: TyCtxt<'_>) -> Vec<String> {
- let mut collector = Collector { args: Vec::new() };
+ let mut collector = Collector { tcx, args: Vec::new() };
tcx.hir().krate().visit_all_item_likes(&mut collector);
for attr in tcx.hir().krate().item.attrs.iter() {
collector.args
}
-struct Collector {
+struct Collector<'tcx> {
+ tcx: TyCtxt<'tcx>,
args: Vec<String>,
}
-impl<'tcx> ItemLikeVisitor<'tcx> for Collector {
+impl<'tcx> ItemLikeVisitor<'tcx> for Collector<'tcx> {
fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) {
let fm = match it.kind {
hir::ItemKind::ForeignMod(ref fm) => fm,
}
// First, add all of the custom #[link_args] attributes
- for m in it.attrs.iter().filter(|a| a.check_name(sym::link_args)) {
+ let sess = &self.tcx.sess;
+ for m in it.attrs.iter().filter(|a| sess.check_name(a, sym::link_args)) {
if let Some(linkarg) = m.value_str() {
self.add_link_args(linkarg);
}
fn visit_impl_item(&mut self, _it: &'tcx hir::ImplItem<'tcx>) {}
}
-impl Collector {
+impl<'tcx> Collector<'tcx> {
fn add_link_args(&mut self, args: Symbol) {
self.args.extend(args.as_str().split(' ').filter(|s| !s.is_empty()).map(|s| s.to_string()))
}
}
// Process all of the #[link(..)]-style arguments
- for m in it.attrs.iter().filter(|a| a.check_name(sym::link)) {
+ let sess = &self.tcx.sess;
+ for m in it.attrs.iter().filter(|a| sess.check_name(a, sym::link)) {
let items = match m.meta_item_list() {
Some(item) => item,
None => continue,
"framework" => NativeLibKind::Framework,
"raw-dylib" => NativeLibKind::RawDylib,
k => {
- struct_span_err!(
- self.tcx.sess,
- item.span(),
- E0458,
- "unknown kind: `{}`",
- k
- )
- .span_label(item.span(), "unknown kind")
- .span_label(m.span, "")
- .emit();
+ struct_span_err!(sess, item.span(), E0458, "unknown kind: `{}`", k)
+ .span_label(item.span(), "unknown kind")
+ .span_label(m.span, "")
+ .emit();
NativeLibKind::Unspecified
}
};
None => continue, // skip like historical compilers
};
if cfg.is_empty() {
- self.tcx.sess.span_err(item.span(), "`cfg()` must have an argument");
+ sess.span_err(item.span(), "`cfg()` must have an argument");
} else if let cfg @ Some(..) = cfg[0].meta_item() {
lib.cfg = cfg.cloned();
} else {
- self.tcx.sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
+ sess.span_err(cfg[0].span(), "invalid argument for `cfg(..)`");
}
} else if item.has_name(sym::wasm_import_module) {
match item.value_str() {
Some(s) => lib.wasm_import_module = Some(s),
None => {
let msg = "must be of the form `#[link(wasm_import_module = \"...\")]`";
- self.tcx.sess.span_err(item.span(), msg);
+ sess.span_err(item.span(), msg);
}
}
} else {
let requires_name = kind_specified || lib.wasm_import_module.is_none();
if lib.name.is_none() && requires_name {
struct_span_err!(
- self.tcx.sess,
+ sess,
m.span,
E0459,
"`#[link(...)]` specified without \
};
SyntaxExtension::new(
- &sess.parse_sess,
+ sess,
kind,
self.get_span(id, sess),
helper_attrs,
// for other constructors correct visibilities
// were already encoded in metadata.
let attrs = self.get_item_attrs(def_id.index, sess);
- if attr::contains_name(&attrs, sym::non_exhaustive) {
+ if sess.contains_name(&attrs, sym::non_exhaustive) {
let crate_def_id = self.local_def_id(CRATE_DEF_INDEX);
vis = ty::Visibility::Restricted(crate_def_id);
}
use crate::rmeta::{self, encoder};
use rustc_ast::ast;
-use rustc_ast::attr;
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_data_structures::svh::Svh;
use rustc_hir as hir;
def_id_arg: ty::query::query_keys::$name<$lt>,
) -> ty::query::query_values::$name<$lt> {
let _prof_timer =
- $tcx.prof.generic_activity("metadata_decode_entry");
+ $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name)));
#[allow(unused_variables)]
let ($def_id, $other) = def_id_arg.into_args();
// Mark the attrs as used
let attrs = data.get_item_attrs(id.index, sess);
for attr in attrs.iter() {
- attr::mark_used(attr);
+ sess.mark_attr_used(attr);
}
let ident = data.item_ident(id.index, sess);
use log::{debug, trace};
use rustc_ast::ast;
-use rustc_ast::attr;
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_data_structures::stable_hasher::StableHasher;
use rustc_data_structures::sync::{join, Lrc};
use rustc_hir as hir;
type_shorthands: FxHashMap<Ty<'tcx>, usize>,
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
- interpret_allocs: FxHashMap<interpret::AllocId, usize>,
- interpret_allocs_inverse: Vec<interpret::AllocId>,
+ interpret_allocs: FxIndexSet<interpret::AllocId>,
// This is used to speed up Span encoding.
// The `usize` is an index into the `MonotonicVec`
fn specialized_encode(&mut self, expn: &ExpnId) -> Result<(), Self::Error> {
rustc_span::hygiene::raw_encode_expn_id(
*expn,
- &mut self.hygiene_ctxt,
+ &self.hygiene_ctxt,
ExpnDataEncodeMode::Metadata,
self,
)
// cross-crate inconsistencies (getting one behavior in the same
// crate, and a different behavior in another crate) due to the
// limited surface that proc-macros can expose.
+ //
+ // IMPORTANT: If this is ever changed, be sure to update
+ // `rustc_span::hygiene::raw_encode_expn_id` to handle
+ // encoding `ExpnData` for proc-macro crates.
if self.is_proc_macro {
SyntaxContext::root().encode(self)?;
} else {
impl<'a, 'tcx> SpecializedEncoder<interpret::AllocId> for EncodeContext<'a, 'tcx> {
fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
- use std::collections::hash_map::Entry;
- let index = match self.interpret_allocs.entry(*alloc_id) {
- Entry::Occupied(e) => *e.get(),
- Entry::Vacant(e) => {
- let idx = self.interpret_allocs_inverse.len();
- self.interpret_allocs_inverse.push(*alloc_id);
- e.insert(idx);
- idx
- }
- };
-
+ let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
index.encode(self)
}
}
let mut n = 0;
trace!("beginning to encode alloc ids");
loop {
- let new_n = self.interpret_allocs_inverse.len();
+ let new_n = self.interpret_allocs.len();
// if we have found new ids, serialize those, too
if n == new_n {
// otherwise, abort
}
trace!("encoding {} further alloc ids", new_n - n);
for idx in n..new_n {
- let id = self.interpret_allocs_inverse[idx];
+ let id = self.interpret_allocs[idx];
let pos = self.position() as u32;
interpret_alloc_index.push(pos);
interpret::specialized_encode_alloc_id(self, tcx, id).unwrap();
let source_map_bytes = self.position() - i;
let attrs = tcx.hir().krate_attrs();
- let has_default_lib_allocator = attr::contains_name(&attrs, sym::default_lib_allocator);
+ let has_default_lib_allocator = tcx.sess.contains_name(&attrs, sym::default_lib_allocator);
let root = self.lazy(CrateRoot {
name: tcx.crate_name(LOCAL_CRATE),
} else {
None
},
- compiler_builtins: attr::contains_name(&attrs, sym::compiler_builtins),
- needs_allocator: attr::contains_name(&attrs, sym::needs_allocator),
- needs_panic_runtime: attr::contains_name(&attrs, sym::needs_panic_runtime),
- no_builtins: attr::contains_name(&attrs, sym::no_builtins),
- panic_runtime: attr::contains_name(&attrs, sym::panic_runtime),
- profiler_runtime: attr::contains_name(&attrs, sym::profiler_runtime),
+ compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins),
+ needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator),
+ needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime),
+ no_builtins: tcx.sess.contains_name(&attrs, sym::no_builtins),
+ panic_runtime: tcx.sess.contains_name(&attrs, sym::panic_runtime),
+ profiler_runtime: tcx.sess.contains_name(&attrs, sym::profiler_runtime),
symbol_mangling_version: tcx.sess.opts.debugging_opts.symbol_mangling_version,
crate_deps,
predicate_shorthands: Default::default(),
source_file_cache: (source_map_files[0].clone(), 0),
interpret_allocs: Default::default(),
- interpret_allocs_inverse: Default::default(),
required_source_files: Some(GrowableBitSet::with_capacity(source_map_files.len())),
is_proc_macro: tcx.sess.crate_types().contains(&CrateType::ProcMacro),
hygiene_ctxt: &hygiene_ctxt,
default: usize,
) {
for attr in &krate.attrs {
- if !attr.check_name(name) {
+ if !sess.check_name(attr, name) {
continue;
}
impl<'tcx> DropckOutlivesResult<'tcx> {
pub fn report_overflows(&self, tcx: TyCtxt<'tcx>, span: Span, ty: Ty<'tcx>) {
- if let Some(overflow_ty) = self.overflows.iter().next() {
+ if let Some(overflow_ty) = self.overflows.get(0) {
let mut err = struct_span_err!(
tcx.sess,
span,
pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound<u128>, Bound<u128>) {
let attrs = self.get_attrs(def_id);
let get = |name| {
- let attr = match attrs.iter().find(|a| a.check_name(name)) {
+ let attr = match attrs.iter().find(|a| self.sess.check_name(a, name)) {
Some(attr) => attr,
None => return Bound::Unbounded,
};
/// we still evaluate them eagerly.
#[inline]
pub fn lazy_normalization(self) -> bool {
- self.features().const_generics || self.features().lazy_normalization_consts
+ let features = self.features();
+ // Note: We do not enable lazy normalization for `features.min_const_generics`.
+ features.const_generics || features.lazy_normalization_consts
}
#[inline]
};
providers.is_panic_runtime = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
- attr::contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)
+ tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::panic_runtime)
};
providers.is_compiler_builtins = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
- attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins)
+ tcx.sess.contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins)
};
providers.has_panic_handler = |tcx, cnum| {
assert_eq!(cnum, LOCAL_CRATE);
}
&ty::Generator(_, ref substs, _) => {
+ self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
+
let substs = substs.as_generator();
let should_remove_further_specializable =
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
&ty::Closure(_, substs) => {
+ self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
+
let substs = substs.as_closure();
let should_remove_further_specializable =
!self.flags.contains(TypeFlags::STILL_FURTHER_SPECIALIZABLE);
}
&ty::FnDef(_, substs) => {
+ self.add_flags(TypeFlags::MAY_POLYMORPHIZE);
+
self.add_substs(substs);
}
self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE)
}
+ /// Does this value contain closures, generators or functions such that it may require
+ /// polymorphization?
+ fn may_polymorphize(&self) -> bool {
+ self.has_type_flags(TypeFlags::MAY_POLYMORPHIZE)
+ }
+
/// A visitor that does not recurse into types, works like `fn walk_shallow` in `Ty`.
fn visit_tys_shallow(&self, visit: impl FnMut(Ty<'tcx>) -> bool) -> bool {
pub struct Visitor<F>(F);
}
if let InstanceDef::Item(def) = self.def {
- let unused = tcx.unused_generic_params(def.did);
-
- if unused.is_empty() {
- // Exit early if every parameter was used.
- return self;
- }
-
- debug!("polymorphize: unused={:?}", unused);
- let polymorphized_substs =
- InternalSubsts::for_item(tcx, def.did, |param, _| match param.kind {
- // If parameter is a const or type parameter..
- ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
- // ..and is within range and unused..
- unused.contains(param.index).unwrap_or(false) =>
- // ..then use the identity for this parameter.
- tcx.mk_param_from_def(param),
- // Otherwise, use the parameter as before.
- _ => self.substs[param.index as usize],
- });
-
+ let polymorphized_substs = polymorphize(tcx, def.did, self.substs);
debug!("polymorphize: self={:?} polymorphized_substs={:?}", self, polymorphized_substs);
Self { def: self.def, substs: polymorphized_substs }
} else {
}
}
+fn polymorphize<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ def_id: DefId,
+ substs: SubstsRef<'tcx>,
+) -> SubstsRef<'tcx> {
+ debug!("polymorphize({:?}, {:?})", def_id, substs);
+ let unused = tcx.unused_generic_params(def_id);
+ debug!("polymorphize: unused={:?}", unused);
+
+ struct PolymorphizationFolder<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ };
+
+ impl ty::TypeFolder<'tcx> for PolymorphizationFolder<'tcx> {
+ fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ debug!("fold_ty: ty={:?}", ty);
+ match ty.kind {
+ ty::Closure(def_id, substs) => {
+ let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+ if substs == polymorphized_substs {
+ ty
+ } else {
+ self.tcx.mk_closure(def_id, polymorphized_substs)
+ }
+ }
+ ty::FnDef(def_id, substs) => {
+ let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+ if substs == polymorphized_substs {
+ ty
+ } else {
+ self.tcx.mk_fn_def(def_id, polymorphized_substs)
+ }
+ }
+ ty::Generator(def_id, substs, movability) => {
+ let polymorphized_substs = polymorphize(self.tcx, def_id, substs);
+ if substs == polymorphized_substs {
+ ty
+ } else {
+ self.tcx.mk_generator(def_id, polymorphized_substs, movability)
+ }
+ }
+ _ => ty.super_fold_with(self),
+ }
+ }
+ }
+
+ InternalSubsts::for_item(tcx, def_id, |param, _| {
+ let is_unused = unused.contains(param.index).unwrap_or(false);
+ debug!("polymorphize: param={:?} is_unused={:?}", param, is_unused);
+ match param.kind {
+ // If parameter is a const or type parameter..
+ ty::GenericParamDefKind::Const | ty::GenericParamDefKind::Type { .. } if
+ // ..and is within range and unused..
+ unused.contains(param.index).unwrap_or(false) =>
+ // ..then use the identity for this parameter.
+ tcx.mk_param_from_def(param),
+
+ // If the parameter does not contain any closures or generators, then use the
+ // substitution directly.
+ _ if !substs.may_polymorphize() => substs[param.index as usize],
+
+ // Otherwise, use the substitution after polymorphizing.
+ _ => {
+ let arg = substs[param.index as usize];
+ let polymorphized_arg = arg.fold_with(&mut PolymorphizationFolder { tcx });
+ debug!("polymorphize: arg={:?} polymorphized_arg={:?}", arg, polymorphized_arg);
+ ty::GenericArg::from(polymorphized_arg)
+ }
+ }
+ })
+}
+
fn needs_fn_once_adapter_shim(
actual_closure_kind: ty::ClosureKind,
trait_closure_kind: ty::ClosureKind,
/// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization?
const STILL_FURTHER_SPECIALIZABLE = 1 << 17;
+
+ /// Does this value contain closures, generators or functions such that it may require
+ /// polymorphization?
+ const MAY_POLYMORPHIZE = 1 << 18;
}
}
let mut max_align: Option<Align> = None;
let mut min_pack: Option<Align> = None;
for attr in tcx.get_attrs(did).iter() {
- for r in attr::find_repr_attrs(&tcx.sess.parse_sess, attr) {
+ for r in attr::find_repr_attrs(&tcx.sess, attr) {
flags.insert(match r {
attr::ReprC => ReprFlags::IS_C,
attr::ReprPacked(pack) => {
}
let attrs = tcx.get_attrs(did);
- if attr::contains_name(&attrs, sym::fundamental) {
+ if tcx.sess.contains_name(&attrs, sym::fundamental) {
flags |= AdtFlags::IS_FUNDAMENTAL;
}
if Some(did) == tcx.lang_items().phantom_data() {
/// Determines whether an item is annotated with an attribute.
pub fn has_attr(self, did: DefId, attr: Symbol) -> bool {
- attr::contains_name(&self.get_attrs(did), attr)
+ self.sess.contains_name(&self.get_attrs(did), attr)
}
/// Returns `true` if this is an `auto trait`.
rustc_data_structures::sync::assert_sync::<tls::ImplicitCtxt<'_, '_>>();
let icx: &tls::ImplicitCtxt<'_, '_> = &*(context as *const tls::ImplicitCtxt<'_, '_>);
- let span_session_globals = rustc_span::SESSION_GLOBALS.with(|ssg| ssg as *const _);
- let span_session_globals = &*span_session_globals;
- let ast_session_globals = rustc_ast::attr::SESSION_GLOBALS.with(|asg| asg as *const _);
- let ast_session_globals = &*ast_session_globals;
+ let session_globals = rustc_span::SESSION_GLOBALS.with(|sg| sg as *const _);
+ let session_globals = &*session_globals;
thread::spawn(move || {
tls::enter_context(icx, |_| {
- rustc_ast::attr::SESSION_GLOBALS.set(ast_session_globals, || {
- rustc_span::SESSION_GLOBALS
- .set(span_session_globals, || tls::with(|tcx| deadlock(tcx, ®istry)))
- });
+ rustc_span::SESSION_GLOBALS
+ .set(session_globals, || tls::with(|tcx| deadlock(tcx, ®istry)))
})
});
}
use crate::ty::context::TyCtxt;
use crate::ty::{self, Ty};
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, OnceCell};
use rustc_data_structures::thin_vec::ThinVec;
use rustc_errors::Diagnostic;
type_shorthands: Default::default(),
predicate_shorthands: Default::default(),
interpret_allocs: Default::default(),
- interpret_allocs_inverse: Vec::new(),
source_map: CachingSourceMapView::new(tcx.sess.source_map()),
file_to_file_index,
hygiene_context: &hygiene_encode_context,
let mut interpret_alloc_index = Vec::new();
let mut n = 0;
loop {
- let new_n = encoder.interpret_allocs_inverse.len();
+ let new_n = encoder.interpret_allocs.len();
// If we have found new IDs, serialize those too.
if n == new_n {
// Otherwise, abort.
}
interpret_alloc_index.reserve(new_n - n);
for idx in n..new_n {
- let id = encoder.interpret_allocs_inverse[idx];
+ let id = encoder.interpret_allocs[idx];
let pos = encoder.position() as u32;
interpret_alloc_index.push(pos);
interpret::specialized_encode_alloc_id(&mut encoder, tcx, id)?;
encoder: &'a mut E,
type_shorthands: FxHashMap<Ty<'tcx>, usize>,
predicate_shorthands: FxHashMap<ty::Predicate<'tcx>, usize>,
- interpret_allocs: FxHashMap<interpret::AllocId, usize>,
- interpret_allocs_inverse: Vec<interpret::AllocId>,
+ interpret_allocs: FxIndexSet<interpret::AllocId>,
source_map: CachingSourceMapView<'tcx>,
file_to_file_index: FxHashMap<*const SourceFile, SourceFileIndex>,
hygiene_context: &'a HygieneEncodeContext,
E: 'a + TyEncoder,
{
fn specialized_encode(&mut self, alloc_id: &interpret::AllocId) -> Result<(), Self::Error> {
- use std::collections::hash_map::Entry;
- let index = match self.interpret_allocs.entry(*alloc_id) {
- Entry::Occupied(e) => *e.get(),
- Entry::Vacant(e) => {
- let idx = self.interpret_allocs_inverse.len();
- self.interpret_allocs_inverse.push(*alloc_id);
- e.insert(idx);
- idx
- }
- };
-
+ let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
index.encode(self)
}
}
use crate::borrow_check::place_ext::PlaceExt;
use crate::dataflow::indexes::BorrowIndex;
use crate::dataflow::move_paths::MoveData;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
use rustc_middle::mir::traversal;
use rustc_middle::mir::visit::{MutatingUseContext, NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Body, Local, Location};
crate struct BorrowSet<'tcx> {
/// The fundamental map relating bitvector indexes to the borrows
- /// in the MIR.
- crate borrows: IndexVec<BorrowIndex, BorrowData<'tcx>>,
-
- /// Each borrow is also uniquely identified in the MIR by the
- /// `Location` of the assignment statement in which it appears on
- /// the right hand side; we map each such location to the
- /// corresponding `BorrowIndex`.
- crate location_map: FxHashMap<Location, BorrowIndex>,
+ /// in the MIR. Each borrow is also uniquely identified in the MIR
+ /// by the `Location` of the assignment statement in which it
+ /// appears on the right hand side. Thus the location is the map
+ /// key, and its position in the map corresponds to `BorrowIndex`.
+ crate location_map: FxIndexMap<Location, BorrowData<'tcx>>,
/// Locations which activate borrows.
/// NOTE: a given location may activate more than one borrow in the future
type Output = BorrowData<'tcx>;
fn index(&self, index: BorrowIndex) -> &BorrowData<'tcx> {
- &self.borrows[index]
+ &self.location_map[index.as_usize()]
}
}
let mut visitor = GatherBorrows {
tcx,
body: &body,
- idx_vec: IndexVec::new(),
location_map: Default::default(),
activation_map: Default::default(),
local_map: Default::default(),
}
BorrowSet {
- borrows: visitor.idx_vec,
location_map: visitor.location_map,
activation_map: visitor.activation_map,
local_map: visitor.local_map,
crate fn activations_at_location(&self, location: Location) -> &[BorrowIndex] {
self.activation_map.get(&location).map(|activations| &activations[..]).unwrap_or(&[])
}
+
+ crate fn len(&self) -> usize {
+ self.location_map.len()
+ }
+
+ crate fn indices(&self) -> impl Iterator<Item = BorrowIndex> {
+ BorrowIndex::from_usize(0)..BorrowIndex::from_usize(self.len())
+ }
+
+ crate fn iter_enumerated(&self) -> impl Iterator<Item = (BorrowIndex, &BorrowData<'tcx>)> {
+ self.indices().zip(self.location_map.values())
+ }
+
+ crate fn get_index_of(&self, location: &Location) -> Option<BorrowIndex> {
+ self.location_map.get_index_of(location).map(BorrowIndex::from)
+ }
+
+ crate fn contains(&self, location: &Location) -> bool {
+ self.location_map.contains_key(location)
+ }
}
struct GatherBorrows<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>,
- idx_vec: IndexVec<BorrowIndex, BorrowData<'tcx>>,
- location_map: FxHashMap<Location, BorrowIndex>,
+ location_map: FxIndexMap<Location, BorrowData<'tcx>>,
activation_map: FxHashMap<Location, Vec<BorrowIndex>>,
local_map: FxHashMap<mir::Local, FxHashSet<BorrowIndex>>,
borrowed_place: *borrowed_place,
assigned_place: *assigned_place,
};
- let idx = self.idx_vec.push(borrow);
- self.location_map.insert(location, idx);
+ let (idx, _) = self.location_map.insert_full(location, borrow);
+ let idx = BorrowIndex::from(idx);
self.insert_as_pending_if_two_phase(location, assigned_place, kind, idx);
//
// TMP = &mut place
if let Some(&borrow_index) = self.pending_activations.get(temp) {
- let borrow_data = &mut self.idx_vec[borrow_index];
+ let borrow_data = &mut self.location_map[borrow_index.as_usize()];
// Watch out: the use of TMP in the borrow itself
// doesn't count as an activation. =)
if let mir::Rvalue::Ref(region, kind, ref place) = *rvalue {
// double-check that we already registered a BorrowData for this
- let borrow_index = self.location_map[&location];
- let borrow_data = &self.idx_vec[borrow_index];
+ let borrow_data = &self.location_map[&location];
assert_eq!(borrow_data.reserve_location, location);
assert_eq!(borrow_data.kind, kind);
assert_eq!(borrow_data.region, region.to_region_vid());
// Consider the borrow not activated to start. When we find an activation, we'll update
// this field.
{
- let borrow_data = &mut self.idx_vec[borrow_index];
+ let borrow_data = &mut self.location_map[borrow_index.as_usize()];
borrow_data.activation_location = TwoPhaseActivation::NotActivated;
}
at borrow_index: {:?} with associated data {:?}",
temp,
old_index,
- self.idx_vec[old_index]
+ self.location_map[old_index.as_usize()]
);
}
}
let places_conflict = places_conflict::places_conflict(
self.infcx.tcx,
self.body,
- self.borrow_set.borrows[borrow_index].borrowed_place,
+ self.borrow_set[borrow_index].borrowed_place,
place,
places_conflict::PlaceConflictBias::NoOverlap,
);
}
}
}
- return normal_ret;
+ normal_ret
}
/// Finds the span of arguments of a closure (within `maybe_closure_span`)
// Invalidate all borrows of local places
let borrow_set = self.borrow_set.clone();
let resume = self.location_table.start_index(resume.start_location());
- for i in borrow_set.borrows.indices() {
- if borrow_of_local_data(borrow_set.borrows[i].borrowed_place) {
+ for (i, data) in borrow_set.iter_enumerated() {
+ if borrow_of_local_data(data.borrowed_place) {
self.all_facts.invalidates.push((resume, i));
}
}
// Invalidate all borrows of local places
let borrow_set = self.borrow_set.clone();
let start = self.location_table.start_index(location);
- for i in borrow_set.borrows.indices() {
- if borrow_of_local_data(borrow_set.borrows[i].borrowed_place) {
+ for (i, data) in borrow_set.iter_enumerated() {
+ if borrow_of_local_data(data.borrowed_place) {
self.all_facts.invalidates.push((start, i));
}
}
let tcx = self.tcx;
let body = self.body;
let borrow_set = self.borrow_set.clone();
- let indices = self.borrow_set.borrows.indices();
+ let indices = self.borrow_set.indices();
each_borrow_involving_path(
self,
tcx,
(
Reservation(WriteKind::MutableBorrow(bk)),
BorrowKind::Shallow | BorrowKind::Shared,
- ) if {
- tcx.migrate_borrowck() && this.borrow_set.location_map.contains_key(&location)
- } =>
- {
- let bi = this.borrow_set.location_map[&location];
+ ) if { tcx.migrate_borrowck() && this.borrow_set.contains(&location) } => {
+ let bi = this.borrow_set.get_index_of(&location).unwrap();
debug!(
"recording invalid reservation of place: {:?} with \
borrow index {:?} as warning",
// the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
// added to the existing number of loans, as if they succeeded them in the set.
//
- let borrow_count = borrow_set.borrows.len();
+ let borrow_count = borrow_set.len();
debug!(
"compute_regions: polonius placeholders, num_universals={}, borrow_count={}",
universal_regions.len(),
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexSet;
use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
use rustc_index::vec::Idx;
use rustc_index::vec::IndexVec;
/// NLL.
#[derive(Default)]
crate struct PlaceholderIndices {
- to_index: FxHashMap<ty::PlaceholderRegion, PlaceholderIndex>,
- from_index: IndexVec<PlaceholderIndex, ty::PlaceholderRegion>,
+ indices: FxIndexSet<ty::PlaceholderRegion>,
}
impl PlaceholderIndices {
crate fn insert(&mut self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
- let PlaceholderIndices { to_index, from_index } = self;
- *to_index.entry(placeholder).or_insert_with(|| from_index.push(placeholder))
+ let (index, _) = self.indices.insert_full(placeholder);
+ index.into()
}
crate fn lookup_index(&self, placeholder: ty::PlaceholderRegion) -> PlaceholderIndex {
- self.to_index[&placeholder]
+ self.indices.get_index_of(&placeholder).unwrap().into()
}
crate fn lookup_placeholder(&self, placeholder: PlaceholderIndex) -> ty::PlaceholderRegion {
- self.from_index[placeholder]
+ self.indices[placeholder.index()]
}
crate fn len(&self) -> usize {
- self.from_index.len()
+ self.indices.len()
}
}
// example).
if let Some(all_facts) = all_facts {
let _prof_timer = self.infcx.tcx.prof.generic_activity("polonius_fact_generation");
- if let Some(borrow_index) = borrow_set.location_map.get(&location) {
+ if let Some(borrow_index) = borrow_set.get_index_of(&location) {
let region_vid = borrow_region.to_region_vid();
all_facts.borrow_region.push((
region_vid,
- *borrow_index,
+ borrow_index,
location_table.mid_index(location),
));
}
let rustc_mir_attrs = attrs
.iter()
- .filter(|attr| attr.check_name(sym::rustc_mir))
+ .filter(|attr| tcx.sess.check_name(attr, sym::rustc_mir))
.flat_map(|attr| attr.meta_item_list().into_iter().flat_map(|v| v.into_iter()));
for attr in rustc_mir_attrs {
borrow_set: &Rc<BorrowSet<'tcx>>,
) -> Self {
let mut borrows_out_of_scope_at_location = FxHashMap::default();
- for (borrow_index, borrow_data) in borrow_set.borrows.iter_enumerated() {
+ for (borrow_index, borrow_data) in borrow_set.iter_enumerated() {
let borrow_region = borrow_data.region.to_region_vid();
- let location = borrow_set.borrows[borrow_index].reserve_location;
+ let location = borrow_data.reserve_location;
precompute_borrows_out_of_scope(
body,
}
pub fn location(&self, idx: BorrowIndex) -> &Location {
- &self.borrow_set.borrows[idx].reserve_location
+ &self.borrow_set[idx].reserve_location
}
/// Add all borrows to the kill set, if those borrows are out of scope at `location`.
places_conflict(
self.tcx,
self.body,
- self.borrow_set.borrows[i].borrowed_place,
+ self.borrow_set[i].borrowed_place,
place,
PlaceConflictBias::NoOverlap,
)
const NAME: &'static str = "borrows";
fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize {
- self.borrow_set.borrows.len() * 2
+ self.borrow_set.len() * 2
}
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut BitSet<Self::Idx>) {
) {
return;
}
- let index = self.borrow_set.location_map.get(&location).unwrap_or_else(|| {
+ let index = self.borrow_set.get_index_of(&location).unwrap_or_else(|| {
panic!("could not find BorrowIndex for location {:?}", location);
});
- trans.gen(*index);
+ trans.gen(index);
}
// Make sure there are no remaining borrows for variables
use rustc_ast::ast::{self, MetaItem};
use rustc_middle::ty;
+use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
pub(crate) use self::drop_flag_effects::*;
pub(crate) param_env: ty::ParamEnv<'tcx>,
}
-pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option<MetaItem> {
+pub(crate) fn has_rustc_mir_with(
+ sess: &Session,
+ attrs: &[ast::Attribute],
+ name: Symbol,
+) -> Option<MetaItem> {
for attr in attrs {
- if attr.check_name(sym::rustc_mir) {
+ if sess.check_name(attr, sym::rustc_mir) {
let items = attr.meta_item_list();
for item in items.iter().flat_map(|l| l.iter()) {
match item.meta_item() {
self,
fold::{TypeFoldable, TypeVisitor},
query::Providers,
+ subst::SubstsRef,
Const, Ty, TyCtxt,
};
use rustc_span::symbol::sym;
) {
debug!("emit_unused_generic_params_error: def_id={:?}", def_id);
let base_def_id = tcx.closure_base_def_id(def_id);
- if !tcx.get_attrs(base_def_id).iter().any(|a| a.check_name(sym::rustc_polymorphize_error)) {
+ if !tcx
+ .get_attrs(base_def_id)
+ .iter()
+ .any(|a| tcx.sess.check_name(a, sym::rustc_polymorphize_error))
+ {
return;
}
unused_parameters: &'a mut FiniteBitSet<u32>,
}
+impl<'a, 'tcx> UsedGenericParametersVisitor<'a, 'tcx> {
+ /// Invoke `unused_generic_params` on a body contained within the current item (e.g.
+ /// a closure, generator or constant).
+ fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) {
+ let unused = self.tcx.unused_generic_params(def_id);
+ debug!(
+ "visit_child_body: unused_parameters={:?} unused={:?}",
+ self.unused_parameters, unused
+ );
+ for (i, arg) in substs.iter().enumerate() {
+ let i = i.try_into().unwrap();
+ if !unused.contains(i).unwrap_or(false) {
+ arg.visit_with(self);
+ }
+ }
+ debug!("visit_child_body: unused_parameters={:?}", self.unused_parameters);
+ }
+}
+
impl<'a, 'tcx> Visitor<'tcx> for UsedGenericParametersVisitor<'a, 'tcx> {
fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
debug!("visit_local_decl: local_decl={:?}", local_decl);
self.unused_parameters.clear(param.index);
false
}
+ ty::ConstKind::Unevaluated(_, _, Some(p)) => {
+ // If there is a promoted, don't look at the substs - since it will always contain
+ // the generic parameters, instead, traverse the promoted MIR.
+ let promoted = self.tcx.promoted_mir(self.def_id);
+ self.visit_body(&promoted[p]);
+ false
+ }
+ ty::ConstKind::Unevaluated(def_id, unevaluated_substs, None) => {
+ self.visit_child_body(def_id.did, unevaluated_substs);
+ false
+ }
_ => c.super_visit_with(self),
}
}
// Consider any generic parameters used by any closures/generators as used in the
// parent.
- let unused = self.tcx.unused_generic_params(def_id);
- debug!(
- "visit_ty: unused_parameters={:?} unused={:?}",
- self.unused_parameters, unused
- );
- for (i, arg) in substs.iter().enumerate() {
- let i = i.try_into().unwrap();
- if !unused.contains(i).unwrap_or(false) {
- arg.visit_with(self);
- }
- }
- debug!("visit_ty: unused_parameters={:?}", self.unused_parameters);
-
+ self.visit_child_body(def_id, substs);
false
}
ty::Param(param) => {
};
use crate::transform::{MirPass, MirSource};
-/// The maximum number of bytes that we'll allocate space for a return value.
+/// The maximum number of bytes that we'll allocate space for a local or the return value.
+/// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
+/// Severely regress performance.
const MAX_ALLOC_LIMIT: u64 = 1024;
/// Macro for machine-specific `InterpError` without allocation.
written_only_inside_own_block_locals: FxHashSet<Local>,
/// Locals that need to be cleared after every block terminates.
only_propagate_inside_block_locals: BitSet<Local>,
+ can_const_prop: IndexVec<Local, ConstPropMode>,
}
impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> {
- fn new(only_propagate_inside_block_locals: BitSet<Local>) -> Self {
+ fn new(
+ only_propagate_inside_block_locals: BitSet<Local>,
+ can_const_prop: IndexVec<Local, ConstPropMode>,
+ ) -> Self {
Self {
stack: Vec::new(),
written_only_inside_own_block_locals: Default::default(),
only_propagate_inside_block_locals,
+ can_const_prop,
}
}
}
local: Local,
) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
{
+ if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
+ throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
+ }
if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) {
ecx.machine.written_only_inside_own_block_locals.insert(local);
}
struct ConstPropagator<'mir, 'tcx> {
ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
tcx: TyCtxt<'tcx>,
- can_const_prop: IndexVec<Local, ConstPropMode>,
param_env: ParamEnv<'tcx>,
// FIXME(eddyb) avoid cloning these two fields more than once,
// by accessing them through `ecx` instead.
let param_env = tcx.param_env_reveal_all_normalized(def_id);
let span = tcx.def_span(def_id);
- let can_const_prop = CanConstProp::check(body);
+ // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts
+ // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in
+ // `layout_of` query invocations.
+ let can_const_prop = CanConstProp::check(tcx, param_env, body);
let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len());
for (l, mode) in can_const_prop.iter_enumerated() {
if *mode == ConstPropMode::OnlyInsideOwnBlock {
tcx,
span,
param_env,
- ConstPropMachine::new(only_propagate_inside_block_locals),
+ ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
(),
);
ecx,
tcx,
param_env,
- can_const_prop,
// FIXME(eddyb) avoid cloning these two fields more than once,
// by accessing them through `ecx` instead.
source_scopes: body.source_scopes.clone(),
fn const_prop(
&mut self,
rvalue: &Rvalue<'tcx>,
- place_layout: TyAndLayout<'tcx>,
source_info: SourceInfo,
place: Place<'tcx>,
) -> Option<()> {
- // #66397: Don't try to eval into large places as that can cause an OOM
- if place_layout.size >= Size::from_bytes(MAX_ALLOC_LIMIT) {
- return None;
- }
-
// Perform any special handling for specific Rvalue types.
// Generally, checks here fall into one of two categories:
// 1. Additional checking to provide useful lints to the user
impl CanConstProp {
/// Returns true if `local` can be propagated
- fn check(body: &Body<'_>) -> IndexVec<Local, ConstPropMode> {
+ fn check(
+ tcx: TyCtxt<'tcx>,
+ param_env: ParamEnv<'tcx>,
+ body: &Body<'tcx>,
+ ) -> IndexVec<Local, ConstPropMode> {
let mut cpv = CanConstProp {
can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
found_assignment: BitSet::new_empty(body.local_decls.len()),
),
};
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
+ let ty = body.local_decls[local].ty;
+ match tcx.layout_of(param_env.and(ty)) {
+ Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
+ // Either the layout fails to compute, then we can't use this local anyway
+ // or the local is too large, then we don't want to.
+ _ => {
+ *val = ConstPropMode::NoPropagation;
+ continue;
+ }
+ }
// Cannot use args at all
// Cannot use locals because if x < y { y - x } else { x - y } would
// lint for x != y
let source_info = statement.source_info;
self.source_info = Some(source_info);
if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
- let place_ty: Ty<'tcx> = place.ty(&self.local_decls, self.tcx).ty;
- if let Ok(place_layout) = self.tcx.layout_of(self.param_env.and(place_ty)) {
- let can_const_prop = self.can_const_prop[place.local];
- if let Some(()) = self.const_prop(rval, place_layout, source_info, place) {
- // This will return None if the above `const_prop` invocation only "wrote" a
- // type whose creation requires no write. E.g. a generator whose initial state
- // consists solely of uninitialized memory (so it doesn't capture any locals).
- if let Some(value) = self.get_const(place) {
- if self.should_const_prop(value) {
- trace!("replacing {:?} with {:?}", rval, value);
- self.replace_with_const(rval, value, source_info);
- if can_const_prop == ConstPropMode::FullConstProp
- || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
- {
- trace!("propagated into {:?}", place);
- }
+ let can_const_prop = self.ecx.machine.can_const_prop[place.local];
+ if let Some(()) = self.const_prop(rval, source_info, place) {
+ // This will return None if the above `const_prop` invocation only "wrote" a
+ // type whose creation requires no write. E.g. a generator whose initial state
+ // consists solely of uninitialized memory (so it doesn't capture any locals).
+ if let Some(value) = self.get_const(place) {
+ if self.should_const_prop(value) {
+ trace!("replacing {:?} with {:?}", rval, value);
+ self.replace_with_const(rval, value, source_info);
+ if can_const_prop == ConstPropMode::FullConstProp
+ || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
+ {
+ trace!("propagated into {:?}", place);
}
}
- match can_const_prop {
- ConstPropMode::OnlyInsideOwnBlock => {
- trace!(
- "found local restricted to its block. \
+ }
+ match can_const_prop {
+ ConstPropMode::OnlyInsideOwnBlock => {
+ trace!(
+ "found local restricted to its block. \
Will remove it from const-prop after block is finished. Local: {:?}",
- place.local
- );
- }
- ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
- trace!("can't propagate into {:?}", place);
- if place.local != RETURN_PLACE {
- Self::remove_const(&mut self.ecx, place.local);
- }
+ place.local
+ );
+ }
+ ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
+ trace!("can't propagate into {:?}", place);
+ if place.local != RETURN_PLACE {
+ Self::remove_const(&mut self.ecx, place.local);
}
- ConstPropMode::FullConstProp => {}
}
- } else {
- // Const prop failed, so erase the destination, ensuring that whatever happens
- // from here on, does not know about the previous value.
- // This is important in case we have
- // ```rust
- // let mut x = 42;
- // x = SOME_MUTABLE_STATIC;
- // // x must now be undefined
- // ```
- // FIXME: we overzealously erase the entire local, because that's easier to
- // implement.
- trace!(
- "propagation into {:?} failed.
- Nuking the entire site from orbit, it's the only way to be sure",
- place,
- );
- Self::remove_const(&mut self.ecx, place.local);
+ ConstPropMode::FullConstProp => {}
}
} else {
+ // Const prop failed, so erase the destination, ensuring that whatever happens
+ // from here on, does not know about the previous value.
+ // This is important in case we have
+ // ```rust
+ // let mut x = 42;
+ // x = SOME_MUTABLE_STATIC;
+ // // x must now be undefined
+ // ```
+ // FIXME: we overzealously erase the entire local, because that's easier to
+ // implement.
trace!(
- "cannot propagate into {:?}, because the type of the local is generic.",
+ "propagation into {:?} failed.
+ Nuking the entire site from orbit, it's the only way to be sure",
place,
);
Self::remove_const(&mut self.ecx, place.local);
fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Vec<usize>> {
let attrs = tcx.get_attrs(def_id);
- let attr = attrs.iter().find(|a| a.check_name(sym::rustc_args_required_const))?;
+ let attr = attrs.iter().find(|a| tcx.sess.check_name(a, sym::rustc_args_required_const))?;
let mut ret = vec![];
for meta in attr.meta_item_list()? {
match meta.literal()?.kind {
// However, we cannot allow stable `const fn`s to use unstable features without an explicit
// opt-in via `allow_internal_unstable`.
- attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
+ attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
.map_or(false, |mut features| features.any(|name| name == feature_gate))
}
// However, we cannot allow stable `const fn`s to use unstable features without an explicit
// opt-in via `allow_internal_unstable`.
- attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
+ attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
.map_or(false, |mut features| features.any(|name| name == feature_gate))
}
let param_env = tcx.param_env(def_id);
let move_data = MoveData::gather_moves(body, tcx, param_env).unwrap();
let mdpe = MoveDataParamEnv { move_data, param_env };
+ let sess = &tcx.sess;
- if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_init).is_some() {
+ if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_init).is_some() {
let flow_inits = MaybeInitializedPlaces::new(tcx, body, &mdpe)
.into_engine(tcx, body, def_id)
.iterate_to_fixpoint();
sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_inits);
}
- if has_rustc_mir_with(&attributes, sym::rustc_peek_maybe_uninit).is_some() {
+ if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_maybe_uninit).is_some() {
let flow_uninits = MaybeUninitializedPlaces::new(tcx, body, &mdpe)
.into_engine(tcx, body, def_id)
.iterate_to_fixpoint();
sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_uninits);
}
- if has_rustc_mir_with(&attributes, sym::rustc_peek_definite_init).is_some() {
+ if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_definite_init).is_some() {
let flow_def_inits = DefinitelyInitializedPlaces::new(tcx, body, &mdpe)
.into_engine(tcx, body, def_id)
.iterate_to_fixpoint();
sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_def_inits);
}
- if has_rustc_mir_with(&attributes, sym::rustc_peek_indirectly_mutable).is_some() {
+ if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_indirectly_mutable).is_some() {
let flow_mut_borrowed = MaybeMutBorrowedLocals::mut_borrows_only(tcx, body, param_env)
.into_engine(tcx, body, def_id)
.iterate_to_fixpoint();
sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_mut_borrowed);
}
- if has_rustc_mir_with(&attributes, sym::rustc_peek_liveness).is_some() {
+ if has_rustc_mir_with(sess, &attributes, sym::rustc_peek_liveness).is_some() {
let flow_liveness =
MaybeLiveLocals.into_engine(tcx, body, def_id).iterate_to_fixpoint();
sanity_check_via_rustc_peek(tcx, body, def_id, &attributes, &flow_liveness);
}
- if has_rustc_mir_with(&attributes, sym::stop_after_dataflow).is_some() {
+ if has_rustc_mir_with(sess, &attributes, sym::stop_after_dataflow).is_some() {
tcx.sess.fatal("stop_after_dataflow ended compilation");
}
}
}
trace!("SUCCESS: optimization applies!");
- return true;
+ true
}
impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
T: Relate<'tcx>,
{
self.relate(a.skip_binder(), b.skip_binder())?;
- Ok(a.clone())
+ Ok(a)
}
}
use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
use crate::thir::{self, *};
use rustc_data_structures::{
- fx::{FxHashMap, FxHashSet},
+ fx::{FxHashSet, FxIndexMap},
stack::ensure_sufficient_stack,
};
use rustc_hir::HirId;
///
/// For `bool` we always generate two edges, one for `true` and one for
/// `false`.
- options: Vec<u128>,
- /// Reverse map used to ensure that the values in `options` are unique.
- indices: FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+ options: FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
},
/// Test for equality with value, possibly after an unsizing coercion to
// may want to add cases based on the candidates that are
// available
match test.kind {
- TestKind::SwitchInt { switch_ty, ref mut options, ref mut indices } => {
+ TestKind::SwitchInt { switch_ty, ref mut options } => {
for candidate in candidates.iter() {
if !self.add_cases_to_switch(
&match_place,
candidate,
switch_ty,
options,
- indices,
) {
break;
}
use crate::build::Builder;
use crate::thir::pattern::compare_const_vals;
use crate::thir::*;
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::RangeEnd;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::*;
// these maps are empty to start; cases are
// added below in add_cases_to_switch
- options: vec![],
- indices: Default::default(),
+ options: Default::default(),
},
}
}
test_place: &Place<'tcx>,
candidate: &Candidate<'pat, 'tcx>,
switch_ty: Ty<'tcx>,
- options: &mut Vec<u128>,
- indices: &mut FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+ options: &mut FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
) -> bool {
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.place == *test_place) {
Some(match_pair) => match_pair,
match *match_pair.pattern.kind {
PatKind::Constant { value } => {
- indices.entry(value).or_insert_with(|| {
- options.push(value.eval_bits(self.hir.tcx(), self.hir.param_env, switch_ty));
- options.len() - 1
+ options.entry(value).or_insert_with(|| {
+ value.eval_bits(self.hir.tcx(), self.hir.param_env, switch_ty)
});
true
}
}
PatKind::Range(range) => {
// Check that none of the switch values are in the range.
- self.values_not_contained_in_range(range, indices).unwrap_or(false)
+ self.values_not_contained_in_range(range, options).unwrap_or(false)
}
PatKind::Slice { .. }
| PatKind::Array { .. }
);
}
- TestKind::SwitchInt { switch_ty, ref options, indices: _ } => {
+ TestKind::SwitchInt { switch_ty, ref options } => {
let target_blocks = make_target_blocks(self);
let terminator = if switch_ty.kind == ty::Bool {
assert!(!options.is_empty() && options.len() <= 2);
TerminatorKind::SwitchInt {
discr: Operand::Copy(place),
switch_ty,
- values: options.clone().into(),
+ values: options.values().copied().collect(),
targets: target_blocks,
}
};
// FIXME(#29623) we could use PatKind::Range to rule
// things out here, in some cases.
(
- &TestKind::SwitchInt { switch_ty: _, options: _, ref indices },
+ &TestKind::SwitchInt { switch_ty: _, ref options },
&PatKind::Constant { ref value },
) if is_switch_ty(match_pair.pattern.ty) => {
- let index = indices[value];
+ let index = options.get_index_of(value).unwrap();
self.candidate_without_match_pair(match_pair_index, candidate);
Some(index)
}
(
- &TestKind::SwitchInt { switch_ty: _, ref options, ref indices },
+ &TestKind::SwitchInt { switch_ty: _, ref options },
&PatKind::Range(range),
) => {
let not_contained =
- self.values_not_contained_in_range(range, indices).unwrap_or(false);
+ self.values_not_contained_in_range(range, options).unwrap_or(false);
if not_contained {
// No switch values are contained in the pattern range,
fn values_not_contained_in_range(
&self,
range: PatRange<'tcx>,
- indices: &FxHashMap<&'tcx ty::Const<'tcx>, usize>,
+ options: &FxIndexMap<&'tcx ty::Const<'tcx>, u128>,
) -> Option<bool> {
- for &val in indices.keys() {
+ for &val in options.keys() {
if self.const_range_contains(range, val)? {
return Some(false);
}
fn should_abort_on_panic(tcx: TyCtxt<'_>, fn_def_id: LocalDefId, _abi: Abi) -> bool {
// Validate `#[unwind]` syntax regardless of platform-specific panic strategy.
let attrs = &tcx.get_attrs(fn_def_id.to_def_id());
- let unwind_attr = attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs);
+ let unwind_attr = attr::find_unwind_attr(&tcx.sess, attrs);
// We never unwind, so it's not relevant to stop an unwind.
if tcx.sess.panic_strategy() != PanicStrategy::Unwind {
use crate::thir::*;
use rustc_ast::ast;
-use rustc_ast::attr;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::Node;
// Some functions always have overflow checks enabled,
// however, they may not get codegen'd, depending on
// the settings for the crate they are codegened in.
- let mut check_overflow = attr::contains_name(attrs, sym::rustc_inherit_overflow_checks);
+ let mut check_overflow = tcx.sess.contains_name(attrs, sym::rustc_inherit_overflow_checks);
// Respect -C overflow-checks.
check_overflow |= tcx.sess.overflow_checks();
-use rustc_ast::token::{self, Token, TokenKind};
+use rustc_ast::token::{self, CommentKind, Token, TokenKind};
use rustc_ast::util::comments;
use rustc_data_structures::sync::Lrc;
use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError};
match token {
rustc_lexer::TokenKind::LineComment => {
let string = self.str_from(start);
- // comments with only more "/"s are not doc comments
- if comments::is_line_doc_comment(string) {
+ if let Some(attr_style) = comments::line_doc_comment_style(string) {
self.forbid_bare_cr(start, string, "bare CR not allowed in doc-comment");
- token::DocComment(Symbol::intern(string))
+ // Opening delimiter of the length 3 is not included into the symbol.
+ token::DocComment(CommentKind::Line, attr_style, Symbol::intern(&string[3..]))
} else {
token::Comment
}
}
rustc_lexer::TokenKind::BlockComment { terminated } => {
let string = self.str_from(start);
- // block comments starting with "/**" or "/*!" are doc-comments
- // but comments with only "*"s between two "/"s are not
- let is_doc_comment = comments::is_block_doc_comment(string);
+ let attr_style = comments::block_doc_comment_style(string, terminated);
if !terminated {
- let msg = if is_doc_comment {
+ let msg = if attr_style.is_some() {
"unterminated block doc-comment"
} else {
"unterminated block comment"
FatalError.raise();
}
- if is_doc_comment {
+ if let Some(attr_style) = attr_style {
self.forbid_bare_cr(start, string, "bare CR not allowed in block doc-comment");
- token::DocComment(Symbol::intern(string))
+ // Opening delimiter of the length 3 and closing delimiter of the length 2
+ // are not included into the symbol.
+ token::DocComment(
+ CommentKind::Block,
+ attr_style,
+ Symbol::intern(&string[3..string.len() - if terminated { 2 } else { 0 }]),
+ )
} else {
token::Comment
}
(&OpenDelim(a), &OpenDelim(b)) | (&CloseDelim(a), &CloseDelim(b)) => a == b,
- (&DocComment(a), &DocComment(b)) | (&Shebang(a), &Shebang(b)) => a == b,
+ (&DocComment(a1, a2, a3), &DocComment(b1, b2, b3)) => a1 == b1 && a2 == b2 && a3 == b3,
+
+ (&Shebang(a), &Shebang(b)) => a == b,
(&Literal(a), &Literal(b)) => a == b,
let item = match attr.kind {
ast::AttrKind::Normal(ref item) => item,
- ast::AttrKind::DocComment(_) => {
+ ast::AttrKind::DocComment(..) => {
let stream = parse_stream_from_source_str(macro_filename, source, sess, Some(span));
builder.push(stream);
continue;
use rustc_ast::ast;
use rustc_ast::attr;
use rustc_ast::token::{self, Nonterminal};
-use rustc_ast::util::comments;
use rustc_ast_pretty::pprust;
use rustc_errors::{error_code, PResult};
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
use log::debug;
let attr = self.parse_attribute_with_inner_parse_policy(inner_parse_policy)?;
attrs.push(attr);
just_parsed_doc_comment = false;
- } else if let token::DocComment(s) = self.token.kind {
- let attr = self.mk_doc_comment(s);
+ } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
+ let attr = attr::mk_doc_comment(comment_kind, attr_style, data, self.token.span);
if attr.style != ast::AttrStyle::Outer {
self.sess
.span_diagnostic
Ok(attrs)
}
- fn mk_doc_comment(&self, s: Symbol) -> ast::Attribute {
- attr::mk_doc_comment(comments::doc_comment_style(s), s, self.token.span)
- }
-
/// Matches `attribute = # ! [ meta_item ]`.
///
/// If `permit_inner` is `true`, then a leading `!` indicates an inner
let attr = self.parse_attribute(true)?;
assert_eq!(attr.style, ast::AttrStyle::Inner);
attrs.push(attr);
- } else if let token::DocComment(s) = self.token.kind {
+ } else if let token::DocComment(comment_kind, attr_style, data) = self.token.kind {
// We need to get the position of this token before we bump.
- let attr = self.mk_doc_comment(s);
+ let attr = attr::mk_doc_comment(comment_kind, attr_style, data, self.token.span);
if attr.style == ast::AttrStyle::Inner {
attrs.push(attr);
self.bump();
}
pub(super) fn eat_incorrect_doc_comment_for_param_type(&mut self) {
- if let token::DocComment(_) = self.token.kind {
+ if let token::DocComment(..) = self.token.kind {
self.struct_span_err(
self.token.span,
"documentation comments cannot be applied to a function parameter's type",
Ok(self.mk_expr(lo.to(self.prev_token.span), kind, attrs))
}
- fn error_missing_in_for_loop(&self) {
- let in_span = self.prev_token.span.between(self.token.span);
- self.struct_span_err(in_span, "missing `in` in `for` loop")
+ fn error_missing_in_for_loop(&mut self) {
+ let (span, msg, sugg) = if self.token.is_ident_named(sym::of) {
+ // Possibly using JS syntax (#75311).
+ let span = self.token.span;
+ self.bump();
+ (span, "try using `in` here instead", "in")
+ } else {
+ (self.prev_token.span.between(self.token.span), "try adding `in` here", " in ")
+ };
+ self.struct_span_err(span, "missing `in` in `for` loop")
.span_suggestion_short(
- in_span,
- "try adding `in` here",
- " in ".into(),
+ span,
+ msg,
+ sugg.into(),
// Has been misleading, at least in the past (closed Issue #48492).
Applicability::MaybeIncorrect,
)
self.expect(&token::Colon)?;
let ty = self.parse_ty()?;
- self.sess.gated_spans.gate(sym::const_generics, const_span.to(self.prev_token.span));
+ self.sess.gated_spans.gate(sym::min_const_generics, const_span.to(self.prev_token.span));
Ok(GenericParam {
ident,
/// Recover on a doc comment before `}`.
fn recover_doc_comment_before_brace(&mut self) -> bool {
- if let token::DocComment(_) = self.token.kind {
+ if let token::DocComment(..) = self.token.kind {
if self.look_ahead(1, |tok| tok == &token::CloseDelim(token::Brace)) {
struct_span_err!(
self.diagnostic(),
self.bump();
}
token::CloseDelim(token::Brace) => {}
- token::DocComment(_) => {
+ token::DocComment(..) => {
let previous_span = self.prev_token.span;
let mut err = self.span_fatal_err(self.token.span, Error::UselessDocComment);
self.bump(); // consume the doc comment
use rustc_ast::ptr::P;
use rustc_ast::token::{self, DelimToken, Token, TokenKind};
use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint};
-use rustc_ast::util::comments::{doc_comment_style, strip_doc_comment_decoration};
use rustc_ast_pretty::pprust;
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult};
use rustc_session::parse::ParseSess;
/// error.
pub(super) unclosed_delims: Vec<UnmatchedBrace>,
last_unexpected_token_span: Option<Span>,
+ /// Span pointing at the `:` for the last type ascription the parser has seen, and whether it
+ /// looked like it could have been a mistyped path or literal `Option:Some(42)`).
pub last_type_ascription: Option<(Span, bool /* likely path typo */)>,
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
subparser_name: Option<&'static str>,
}
fn next_desugared(&mut self) -> Token {
- let (name, sp) = match self.next() {
- Token { kind: token::DocComment(name), span } => (name, span),
+ let (data, attr_style, sp) = match self.next() {
+ Token { kind: token::DocComment(_, attr_style, data), span } => {
+ (data, attr_style, span)
+ }
tok => return tok,
};
- let stripped = strip_doc_comment_decoration(name);
-
// Searches for the occurrences of `"#*` and returns the minimum number of `#`s
// required to wrap the text.
let mut num_of_hashes = 0;
let mut count = 0;
- for ch in stripped.chars() {
+ for ch in data.as_str().chars() {
count = match ch {
'"' => 1,
'#' if count > 0 => count + 1,
[
TokenTree::token(token::Ident(sym::doc, false), sp),
TokenTree::token(token::Eq, sp),
- TokenTree::token(
- TokenKind::lit(token::StrRaw(num_of_hashes), Symbol::intern(&stripped), None),
- sp,
- ),
+ TokenTree::token(TokenKind::lit(token::StrRaw(num_of_hashes), data, None), sp),
]
.iter()
.cloned()
TokenCursorFrame::new(
delim_span,
token::NoDelim,
- &if doc_comment_style(name) == AttrStyle::Inner {
+ &if attr_style == AttrStyle::Inner {
[TokenTree::token(token::Pound, sp), TokenTree::token(token::Not, sp), body]
.iter()
.cloned()
}
let r_start = str_style.map(|r| r + 1).unwrap_or(0);
- let r_end = str_style.map(|r| r).unwrap_or(0);
+ let r_end = str_style.unwrap_or(0);
let s = &snippet[r_start + 1..snippet.len() - r_end - 1];
(find_skips(s, str_style.is_some()), true)
}
use rustc_middle::ty::TyCtxt;
use rustc_ast::ast::{Attribute, NestedMetaItem};
-use rustc_ast::attr;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
) {
let mut is_valid = true;
for attr in attrs {
- is_valid &= if attr.check_name(sym::inline) {
+ is_valid &= if self.tcx.sess.check_name(attr, sym::inline) {
self.check_inline(hir_id, attr, span, target)
- } else if attr.check_name(sym::non_exhaustive) {
+ } else if self.tcx.sess.check_name(attr, sym::non_exhaustive) {
self.check_non_exhaustive(attr, span, target)
- } else if attr.check_name(sym::marker) {
+ } else if self.tcx.sess.check_name(attr, sym::marker) {
self.check_marker(attr, span, target)
- } else if attr.check_name(sym::target_feature) {
+ } else if self.tcx.sess.check_name(attr, sym::target_feature) {
self.check_target_feature(attr, span, target)
- } else if attr.check_name(sym::track_caller) {
+ } else if self.tcx.sess.check_name(attr, sym::track_caller) {
self.check_track_caller(&attr.span, attrs, span, target)
- } else if attr.check_name(sym::doc) {
+ } else if self.tcx.sess.check_name(attr, sym::doc) {
self.check_doc_alias(attr)
} else {
true
target: Target,
) -> bool {
match target {
- _ if attr::contains_name(attrs, sym::naked) => {
+ _ if self.tcx.sess.contains_name(attrs, sym::naked) => {
struct_span_err!(
self.tcx.sess,
*attr_span,
// ```
let hints: Vec<_> = attrs
.iter()
- .filter(|attr| attr.check_name(sym::repr))
+ .filter(|attr| self.tcx.sess.check_name(attr, sym::repr))
.filter_map(|attr| attr.meta_item_list())
.flatten()
.collect();
// When checking statements ignore expressions, they will be checked later
if let hir::StmtKind::Local(ref l) = stmt.kind {
for attr in l.attrs.iter() {
- if attr.check_name(sym::inline) {
+ if self.tcx.sess.check_name(attr, sym::inline) {
self.check_inline(l.hir_id, attr, &stmt.span, Target::Statement);
}
- if attr.check_name(sym::repr) {
+ if self.tcx.sess.check_name(attr, sym::repr) {
self.emit_repr_error(
attr.span,
stmt.span,
_ => Target::Expression,
};
for attr in expr.attrs.iter() {
- if attr.check_name(sym::inline) {
+ if self.tcx.sess.check_name(attr, sym::inline) {
self.check_inline(expr.hir_id, attr, &expr.span, target);
}
- if attr.check_name(sym::repr) {
+ if self.tcx.sess.check_name(attr, sym::repr) {
self.emit_repr_error(
attr.span,
expr.span,
fn check_used(&self, attrs: &'hir [Attribute], target: Target) {
for attr in attrs {
- if attr.check_name(sym::used) && target != Target::Static {
+ if self.tcx.sess.check_name(attr, sym::used) && target != Target::Static {
self.tcx
.sess
.span_err(attr.span, "attribute must be applied to a `static` variable");
// However, we cannot allow stable `const fn`s to use unstable features without an explicit
// opt-in via `allow_internal_unstable`.
- attr::allow_internal_unstable(&tcx.get_attrs(def_id), &tcx.sess.diagnostic())
+ attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id))
.map_or(false, |mut features| features.any(|name| name == feature_gate))
};
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::lint;
-use rustc_ast::{ast, attr};
+use rustc_ast::ast;
use rustc_span::symbol::{sym, Symbol};
// Any local node that may call something in its body block should be
id: hir::HirId,
attrs: &[ast::Attribute],
) -> bool {
- if attr::contains_name(attrs, sym::lang) {
+ if tcx.sess.contains_name(attrs, sym::lang) {
return true;
}
// Stable attribute for #[lang = "panic_impl"]
- if attr::contains_name(attrs, sym::panic_handler) {
+ if tcx.sess.contains_name(attrs, sym::panic_handler) {
return true;
}
// (To be) stable attribute for #[lang = "oom"]
- if attr::contains_name(attrs, sym::alloc_error_handler) {
+ if tcx.sess.contains_name(attrs, sym::alloc_error_handler) {
return true;
}
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
+use rustc_session::Session;
use rustc_span::symbol::{sym, Symbol};
struct DiagnosticItemCollector<'tcx> {
}
fn observe_item(&mut self, attrs: &[ast::Attribute], hir_id: hir::HirId) {
- if let Some(name) = extract(attrs) {
+ if let Some(name) = extract(&self.tcx.sess, attrs) {
let def_id = self.tcx.hir().local_def_id(hir_id);
// insert into our table
collect_item(self.tcx, &mut self.items, name, def_id.to_def_id());
}
/// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes.
-fn extract(attrs: &[ast::Attribute]) -> Option<Symbol> {
+fn extract(sess: &Session, attrs: &[ast::Attribute]) -> Option<Symbol> {
attrs.iter().find_map(|attr| {
- if attr.check_name(sym::rustc_diagnostic_item) { attr.value_str() } else { None }
+ if sess.check_name(attr, sym::rustc_diagnostic_item) { attr.value_str() } else { None }
})
}
-use rustc_ast::attr;
use rustc_ast::entry::EntryPointType;
use rustc_errors::struct_span_err;
use rustc_hir::def_id::{CrateNum, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
}
// If the user wants no main function at all, then stop here.
- if attr::contains_name(&tcx.hir().krate().item.attrs, sym::no_main) {
+ if tcx.sess.contains_name(&tcx.hir().krate().item.attrs, sym::no_main) {
return None;
}
configure_main(tcx, &ctxt)
}
-// Beware, this is duplicated in `librustc_ast/entry.rs`, so make sure to keep
-// them in sync.
-fn entry_point_type(item: &Item<'_>, at_root: bool) -> EntryPointType {
+// Beware, this is duplicated in `librustc_builtin_macros/test_harness.rs`
+// (with `ast::Item`), so make sure to keep them in sync.
+fn entry_point_type(sess: &Session, item: &Item<'_>, at_root: bool) -> EntryPointType {
match item.kind {
ItemKind::Fn(..) => {
- if attr::contains_name(&item.attrs, sym::start) {
+ if sess.contains_name(&item.attrs, sym::start) {
EntryPointType::Start
- } else if attr::contains_name(&item.attrs, sym::main) {
+ } else if sess.contains_name(&item.attrs, sym::main) {
EntryPointType::MainAttr
} else if item.ident.name == sym::main {
if at_root {
}
fn find_item(item: &Item<'_>, ctxt: &mut EntryContext<'_, '_>, at_root: bool) {
- match entry_point_type(item, at_root) {
+ match entry_point_type(&ctxt.session, item, at_root) {
EntryPointType::MainNamed => {
if ctxt.main_fn.is_none() {
ctxt.main_fn = Some((item.hir_id, item.span));
}
fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId, attrs: &[Attribute]) {
- if let Some((value, span)) = extract(&attrs) {
+ let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym);
+ if let Some((value, span)) = extract(check_name, &attrs) {
match ITEM_REFS.get(&value).cloned() {
// Known lang item with attribute on correct target.
Some((item_index, expected_target)) if actual_target == expected_target => {
| ItemKind::Struct(..)
| ItemKind::Union(..) => {
for attr in self.tcx.get_attrs(item_def_id.to_def_id()).iter() {
- if attr.check_name(sym::rustc_layout) {
+ if self.tcx.sess.check_name(attr, sym::rustc_layout) {
self.dump_layout_of(item_def_id, item, attr);
}
}
// Find a stability attribute (i.e., `#[stable (..)]`, `#[unstable (..)]`,
// `#[rustc_const_unstable (..)]`).
- if let Some(stab_attr) = stab_attrs.iter().find(|stab_attr| attr.check_name(**stab_attr)) {
+ if let Some(stab_attr) =
+ stab_attrs.iter().find(|stab_attr| self.tcx.sess.check_name(attr, **stab_attr))
+ {
let meta_item = attr.meta();
if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta_item {
let mut feature = None;
if let FnKind::Method(..) = fk {
let parent = ir.tcx.hir().get_parent_item(id);
if let Some(Node::Item(i)) = ir.tcx.hir().find(parent) {
- if i.attrs.iter().any(|a| a.check_name(sym::automatically_derived)) {
+ if i.attrs.iter().any(|a| ir.tcx.sess.check_name(a, sym::automatically_derived)) {
return;
}
}
did_error = self.forbid_staged_api_attrs(hir_id, attrs);
}
- let depr = if did_error {
- None
- } else {
- attr::find_deprecation(&self.tcx.sess.parse_sess, attrs, item_sp)
- };
+ let depr =
+ if did_error { None } else { attr::find_deprecation(&self.tcx.sess, attrs, item_sp) };
let mut is_deprecated = false;
if let Some(depr) = &depr {
is_deprecated = true;
}
if self.tcx.features().staged_api {
- if let Some(..) = attrs.iter().find(|a| a.check_name(sym::deprecated)) {
+ if let Some(..) = attrs.iter().find(|a| self.tcx.sess.check_name(a, sym::deprecated)) {
self.tcx.sess.span_err(
item_sp,
"`#[deprecated]` cannot be used in staged API; \
return;
}
- let (stab, const_stab) = attr::find_stability(&self.tcx.sess.parse_sess, attrs, item_sp);
+ let (stab, const_stab) = attr::find_stability(&self.tcx.sess, attrs, item_sp);
let const_stab = const_stab.map(|const_stab| {
let const_stab = self.tcx.intern_const_stability(const_stab);
for attr in attrs {
let name = attr.name_or_empty();
if unstable_attrs.contains(&name) {
- attr::mark_used(attr);
+ self.tcx.sess.mark_attr_used(attr);
struct_span_err!(
self.tcx.sess,
attr.span,
}
fn visit_foreign_item(&mut self, i: &hir::ForeignItem<'_>) {
- if let Some((lang_item, _)) = hir::lang_items::extract(&i.attrs) {
+ let check_name = |attr, sym| self.tcx.sess.check_name(attr, sym);
+ if let Some((lang_item, _)) = hir::lang_items::extract(check_name, &i.attrs) {
self.register(lang_item, i.span, i.hir_id);
}
intravisit::walk_foreign_item(self, i)
//! Used by `rustc` when compiling a plugin crate.
-use rustc_ast::attr;
use rustc_hir as hir;
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::itemlikevisit::ItemLikeVisitor;
use rustc_span::symbol::sym;
use rustc_span::Span;
-struct RegistrarFinder {
+struct RegistrarFinder<'tcx> {
+ tcx: TyCtxt<'tcx>,
registrars: Vec<(hir::HirId, Span)>,
}
-impl<'v> ItemLikeVisitor<'v> for RegistrarFinder {
+impl<'v, 'tcx> ItemLikeVisitor<'v> for RegistrarFinder<'tcx> {
fn visit_item(&mut self, item: &hir::Item<'_>) {
if let hir::ItemKind::Fn(..) = item.kind {
- if attr::contains_name(&item.attrs, sym::plugin_registrar) {
+ if self.tcx.sess.contains_name(&item.attrs, sym::plugin_registrar) {
self.registrars.push((item.hir_id, item.span));
}
}
fn plugin_registrar_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<DefId> {
assert_eq!(cnum, LOCAL_CRATE);
- let mut finder = RegistrarFinder { registrars: Vec::new() };
+ let mut finder = RegistrarFinder { tcx, registrars: Vec::new() };
tcx.hir().krate().visit_all_item_likes(&mut finder);
match finder.registrars.len() {
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")]
#![feature(nll)]
+#![recursion_limit = "256"]
use rustc_lint::LintStore;
let mut plugins = Vec::new();
for attr in &krate.attrs {
- if !attr.check_name(sym::plugin) {
+ if !sess.check_name(attr, sym::plugin) {
continue;
}
Node::Item(item) => &item.vis,
Node::ForeignItem(foreign_item) => &foreign_item.vis,
Node::MacroDef(macro_def) => {
- if attr::contains_name(¯o_def.attrs, sym::macro_export) {
+ if tcx.sess.contains_name(¯o_def.attrs, sym::macro_export) {
return (ty::Visibility::Public, macro_def.span, "public");
} else {
¯o_def.vis
ctor_vis =
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
let attrs = tcx.get_attrs(variant.def_id);
- span =
- attr::find_by_name(&attrs, sym::non_exhaustive).unwrap().span;
+ span = tcx
+ .sess
+ .find_by_name(&attrs, sym::non_exhaustive)
+ .unwrap()
+ .span;
descr = "crate-visible";
}
if adt_def.non_enum_variant().is_field_list_non_exhaustive() {
ctor_vis =
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
- span = attr::find_by_name(&item.attrs, sym::non_exhaustive)
+ span = tcx
+ .sess
+ .find_by_name(&item.attrs, sym::non_exhaustive)
.unwrap()
.span;
descr = "crate-visible";
}
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
- if attr::find_transparency(&md.attrs, md.ast.macro_rules).0 != Transparency::Opaque {
+ if attr::find_transparency(&self.tcx.sess, &md.attrs, md.ast.macro_rules).0
+ != Transparency::Opaque
+ {
self.update(md.hir_id, Some(AccessLevel::Public));
return;
}
}
ast::UseTreeKind::Glob => {
let kind = ImportKind::Glob {
- is_prelude: attr::contains_name(&item.attrs, sym::prelude_import),
+ is_prelude: self.r.session.contains_name(&item.attrs, sym::prelude_import),
max_vis: Cell::new(ty::Visibility::Invisible),
};
self.add_import(prefix, kind, use_tree.span, id, item, root_span, item.id, vis);
let module_kind = ModuleKind::Def(DefKind::Mod, def_id.to_def_id(), ident.name);
let module = self.r.arenas.alloc_module(ModuleData {
no_implicit_prelude: parent.no_implicit_prelude || {
- attr::contains_name(&item.attrs, sym::no_implicit_prelude)
+ self.r.session.contains_name(&item.attrs, sym::no_implicit_prelude)
},
..ModuleData::new(
Some(parent),
// If the structure is marked as non_exhaustive then lower the visibility
// to within the crate.
let mut ctor_vis = if vis == ty::Visibility::Public
- && attr::contains_name(&item.attrs, sym::non_exhaustive)
+ && self.r.session.contains_name(&item.attrs, sym::non_exhaustive)
{
ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))
} else {
let mut import_all = None;
let mut single_imports = Vec::new();
for attr in &item.attrs {
- if attr.check_name(sym::macro_use) {
+ if self.r.session.check_name(attr, sym::macro_use) {
if self.parent_scope.module.parent.is_some() {
struct_span_err!(
self.r.session,
/// Returns `true` if this attribute list contains `macro_use`.
fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool {
for attr in attrs {
- if attr.check_name(sym::macro_escape) {
+ if self.r.session.check_name(attr, sym::macro_escape) {
let msg = "`#[macro_escape]` is a deprecated synonym for `#[macro_use]`";
let mut err = self.r.session.struct_span_warn(attr.span, msg);
if let ast::AttrStyle::Inner = attr.style {
} else {
err.emit();
}
- } else if !attr.check_name(sym::macro_use) {
+ } else if !self.r.session.check_name(attr, sym::macro_use) {
continue;
}
MacroRulesScope::Invocation(invoc_id)
}
- fn proc_macro_stub(item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
- if attr::contains_name(&item.attrs, sym::proc_macro) {
+ fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
+ if self.r.session.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) {
+ } else if self.r.session.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) {
+ } else if let Some(attr) = self.r.session.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));
let ext = Lrc::new(self.r.compile_macro(item, self.r.session.edition()));
(ext, item.ident, item.span, def.macro_rules)
}
- ItemKind::Fn(..) => match Self::proc_macro_stub(item) {
+ ItemKind::Fn(..) => match self.proc_macro_stub(item) {
Some((macro_kind, ident, span)) => {
self.r.proc_macro_stubs.insert(def_id);
(self.r.dummy_ext(macro_kind), ident, span, false)
if macro_rules {
let ident = ident.normalize_to_macros_2_0();
self.r.macro_names.insert(ident);
- let is_macro_export = attr::contains_name(&item.attrs, sym::macro_export);
+ let is_macro_export = self.r.session.contains_name(&item.attrs, sym::macro_export);
let vis = if is_macro_export {
ty::Visibility::Public
} else {
// If the variant is marked as non_exhaustive then lower the visibility to within the
// crate.
let mut ctor_vis = vis;
- let has_non_exhaustive = attr::contains_name(&variant.attrs, sym::non_exhaustive);
+ let has_non_exhaustive = self.r.session.contains_name(&variant.attrs, sym::non_exhaustive);
if has_non_exhaustive && vis == ty::Visibility::Public {
ctor_vis = ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX));
}
);
err
}
+ ResolutionError::ParamInNonTrivialAnonConst(name) => {
+ let mut err = self.session.struct_span_err(
+ span,
+ "generic parameters must not be used inside of non trivial constant values",
+ );
+ err.span_label(
+ span,
+ &format!(
+ "non-trivial anonymous constants must not depend on the parameter `{}`",
+ name
+ ),
+ );
+ err.help(
+ &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name)
+ );
+ err
+ }
ResolutionError::SelfInTyParamDefault => {
let mut err = struct_span_err!(
self.session,
) = binding.kind
{
let def_id = (&*self).parent(ctor_def_id).expect("no parent for a constructor");
- if let Some(fields) = self.field_names.get(&def_id) {
- let first_field = fields.first().expect("empty field list in the map");
- return Some(fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)));
- }
+ let fields = self.field_names.get(&def_id)?;
+ let first_field = fields.first()?; // Handle `struct Foo()`
+ return Some(fields.iter().fold(first_field.span, |acc, field| acc.to(field.span)));
}
None
}
ItemRibKind(HasGenericParams),
/// We're in a constant item. Can't refer to dynamic stuff.
- ConstantItemRibKind,
+ ConstantItemRibKind(bool),
/// We passed through a module.
ModuleRibKind(Module<'a>),
NormalRibKind
| ClosureOrAsyncRibKind
| FnItemRibKind
- | ConstantItemRibKind
+ | ConstantItemRibKind(_)
| ModuleRibKind(_)
| MacroDefinition(_)
| ConstParamTyRibKind => false,
ValueNS => "method or associated constant",
MacroNS => bug!("associated macro"),
},
- PathSource::Expr(parent) => match &parent.as_ref().map(|p| &p.kind) {
+ PathSource::Expr(parent) => match parent.as_ref().map(|p| &p.kind) {
// "function" here means "anything callable" rather than `DefKind::Fn`,
// this is not precise but usually more helpful than just "value".
Some(ExprKind::Call(call_expr, _)) => match &call_expr.kind {
}
fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
debug!("visit_anon_const {:?}", constant);
- self.with_constant_rib(|this| {
+ self.with_constant_rib(constant.value.is_potential_trivial_const_param(), |this| {
visit::walk_anon_const(this, constant);
});
}
if !check_ns(TypeNS) && check_ns(ValueNS) {
// This must be equivalent to `visit_anon_const`, but we cannot call it
// directly due to visitor lifetimes so we have to copy-paste some code.
- self.with_constant_rib(|this| {
+ self.with_constant_rib(true, |this| {
this.smart_resolve_path(
ty.id,
qself.as_ref(),
| ClosureOrAsyncRibKind
| FnItemRibKind
| ItemRibKind(..)
- | ConstantItemRibKind
+ | ConstantItemRibKind(_)
| ModuleRibKind(..)
| ForwardTyParamBanRibKind
| ConstParamTyRibKind => {
// Only impose the restrictions of `ConstRibKind` for an
// actual constant expression in a provided default.
if let Some(expr) = default {
- this.with_constant_rib(|this| this.visit_expr(expr));
+ // We allow arbitrary const expressions inside of associated consts,
+ // even if they are potentially not const evaluatable.
+ //
+ // Type parameters can already be used and as associated consts are
+ // not used as part of the type system, this is far less surprising.
+ this.with_constant_rib(true, |this| {
+ this.visit_expr(expr)
+ });
}
}
AssocItemKind::Fn(_, _, generics, _) => {
self.with_item_rib(HasGenericParams::No, |this| {
this.visit_ty(ty);
if let Some(expr) = expr {
- this.with_constant_rib(|this| this.visit_expr(expr));
+ this.with_constant_rib(expr.is_potential_trivial_const_param(), |this| {
+ this.visit_expr(expr)
+ });
}
});
}
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
}
- fn with_constant_rib(&mut self, f: impl FnOnce(&mut Self)) {
+ fn with_constant_rib(&mut self, trivial: bool, f: impl FnOnce(&mut Self)) {
debug!("with_constant_rib");
- self.with_rib(ValueNS, ConstantItemRibKind, |this| {
- this.with_rib(TypeNS, ConstantItemRibKind, |this| {
- this.with_label_rib(ConstantItemRibKind, f);
+ self.with_rib(ValueNS, ConstantItemRibKind(trivial), |this| {
+ this.with_rib(TypeNS, ConstantItemRibKind(trivial), |this| {
+ this.with_label_rib(ConstantItemRibKind(trivial), f);
})
});
}
for item in impl_items {
use crate::ResolutionError::*;
match &item.kind {
- AssocItemKind::Const(..) => {
+ AssocItemKind::Const(_default, _ty, _expr) => {
debug!("resolve_implementation AssocItemKind::Const",);
// If this is a trait impl, ensure the const
// exists in trait
|n, s| ConstNotMemberOfTrait(n, s),
);
- this.with_constant_rib(|this| {
+ // We allow arbitrary const expressions inside of associated consts,
+ // even if they are potentially not const evaluatable.
+ //
+ // Type parameters can already be used and as associated consts are
+ // not used as part of the type system, this is far less surprising.
+ this.with_constant_rib(true, |this| {
visit::walk_assoc_item(this, item, AssocCtxt::Impl)
});
}
//! way. Therefore, we break lifetime name resolution into a separate pass.
use crate::late::diagnostics::{ForLifetimeSpanType, MissingLifetimeSpot};
-use rustc_ast::attr;
use rustc_ast::walk_list;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
let result = object_lifetime_defaults_for_item(tcx, generics);
// Debugging aid.
- if attr::contains_name(&item.attrs, sym::rustc_object_lifetime_default) {
+ if tcx.sess.contains_name(&item.attrs, sym::rustc_object_lifetime_default) {
let object_lifetime_default_reprs: String = result
.iter()
.map(|set| match *set {
if let Some(def_id) = parent_def_id.as_local() {
let parent_hir_id = self.tcx.hir().as_local_hir_id(def_id);
// lifetimes in `derive` expansions don't count (Issue #53738)
- if self
- .tcx
- .hir()
- .attrs(parent_hir_id)
- .iter()
- .any(|attr| attr.check_name(sym::automatically_derived))
- {
+ if self.tcx.hir().attrs(parent_hir_id).iter().any(|attr| {
+ self.tcx.sess.check_name(attr, sym::automatically_derived)
+ }) {
continue;
}
}
use rustc_ast::ast::{self, FloatTy, IntTy, NodeId, UintTy};
use rustc_ast::ast::{Crate, CRATE_NODE_ID};
use rustc_ast::ast::{ItemKind, Path};
-use rustc_ast::attr;
use rustc_ast::node_id::NodeMap;
use rustc_ast::unwrap_or;
use rustc_ast::visit::{self, Visitor};
ParamInTyOfConstParam(Symbol),
/// constant values inside of type parameter defaults must not depend on generic parameters.
ParamInAnonConstInTyDefault(Symbol),
+ /// generic parameters must not be used inside of non trivial constant values.
+ ///
+ /// This error is only emitted when using `min_const_generics`.
+ ParamInNonTrivialAnonConst(Symbol),
/// Error E0735: type parameters with a default cannot use `Self`
SelfInTyParamDefault,
/// Error E0767: use of unreachable label
let root_def_id = DefId::local(CRATE_DEF_INDEX);
let root_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
let graph_root = arenas.alloc_module(ModuleData {
- no_implicit_prelude: attr::contains_name(&krate.attrs, sym::no_implicit_prelude),
+ no_implicit_prelude: session.contains_name(&krate.attrs, sym::no_implicit_prelude),
..ModuleData::new(None, root_module_kind, root_def_id, ExpnId::root(), krate.span)
});
let empty_module_kind = ModuleKind::Def(DefKind::Mod, root_def_id, kw::Invalid);
.map(|(name, _)| (Ident::from_str(name), Default::default()))
.collect();
- if !attr::contains_name(&krate.attrs, sym::no_core) {
+ if !session.contains_name(&krate.attrs, sym::no_core) {
extern_prelude.insert(Ident::with_dummy_span(sym::core), Default::default());
- if !attr::contains_name(&krate.attrs, sym::no_std) {
+ if !session.contains_name(&krate.attrs, sym::no_std) {
extern_prelude.insert(Ident::with_dummy_span(sym::std), Default::default());
if session.rust_2018() {
extern_prelude.insert(Ident::with_dummy_span(sym::meta), Default::default());
res_err = Some(CannotCaptureDynamicEnvironmentInFnItem);
}
}
- ConstantItemRibKind => {
+ ConstantItemRibKind(_) => {
// Still doesn't deal with upvars
if record_used {
self.report_error(span, AttemptToUseNonConstantValueInConstant);
in_ty_param_default = true;
continue;
}
- ConstantItemRibKind => {
+ ConstantItemRibKind(trivial) => {
+ // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
+ if !trivial && self.session.features_untracked().min_const_generics {
+ if record_used {
+ self.report_error(
+ span,
+ ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
+ );
+ }
+ return Res::Err;
+ }
+
if in_ty_param_default {
if record_used {
self.report_error(
in_ty_param_default = true;
continue;
}
- ConstantItemRibKind => {
+ ConstantItemRibKind(trivial) => {
+ // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
+ if !trivial && self.session.features_untracked().min_const_generics {
+ if record_used {
+ self.report_error(
+ span,
+ ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name),
+ );
+ }
+ return Res::Err;
+ }
+
if in_ty_param_default {
if record_used {
self.report_error(
use rustc_ast::ast::{self, NodeId};
use rustc_ast_lowering::ResolverAstLowering;
use rustc_ast_pretty::pprust;
-use rustc_attr::{self as attr, StabilityLevel};
+use rustc_attr::StabilityLevel;
use rustc_data_structures::fx::FxHashSet;
use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
use rustc_expand::compile_declarative_macro;
descr: &str,
) -> FxHashSet<Ident> {
let mut registered = FxHashSet::default();
- for attr in attr::filter_by_name(attrs, attr_name) {
+ for attr in sess.filter_by_name(attrs, attr_name) {
for nested_meta in attr.meta_item_list().unwrap_or_default() {
match nested_meta.ident() {
Some(ident) => {
/// its expander to a pre-defined one for built-in macros.
crate fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> SyntaxExtension {
let mut result = compile_declarative_macro(
- &self.session.parse_sess,
+ &self.session,
self.session.features_untracked(),
item,
edition,
mod sig;
use rustc_ast::ast::{self};
-use rustc_ast::util::comments::strip_doc_comment_decoration;
+use rustc_ast::util::comments::beautify_doc_string;
use rustc_ast_pretty::pprust::attribute_to_string;
use rustc_hir as hir;
use rustc_hir::def::{DefKind as HirDefKind, Res};
Res::Def(HirDefKind::ConstParam, def_id) => {
Some(Ref { kind: RefKind::Variable, span, ref_id: id_from_def_id(def_id) })
}
- Res::Def(HirDefKind::Ctor(_, ..), def_id) => {
+ Res::Def(HirDefKind::Ctor(..), def_id) => {
// This is a reference to a tuple struct or an enum variant where the def_id points
// to an invisible constructor function. That is not a very useful
// def, so adjust to point to the tuple struct or enum variant itself.
for attr in attrs {
if let Some(val) = attr.doc_str() {
- if attr.is_doc_comment() {
- result.push_str(&strip_doc_comment_decoration(val));
- } else {
- result.push_str(&val.as_str());
- }
+ // FIXME: Should save-analysis beautify doc strings itself or leave it to users?
+ result.push_str(&beautify_doc_string(val));
result.push('\n');
- } else if attr.check_name(sym::doc) {
+ } else if self.tcx.sess.check_name(attr, sym::doc) {
if let Some(meta_list) = attr.meta_item_list() {
meta_list
.into_iter()
p.push(RUST_LIB_DIR);
p.push(&self.triple);
p.push("bin");
- if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p.clone()] }
+ if self_contained { vec![p.clone(), p.join("self-contained")] } else { vec![p] }
}
}
//! Related to out filenames of compilation (e.g. save analysis, binaries).
use crate::config::{CrateType, Input, OutputFilenames, OutputType};
use crate::Session;
-use rustc_ast::{ast, attr};
+use rustc_ast::ast;
use rustc_span::symbol::sym;
use rustc_span::Span;
use std::path::{Path, PathBuf};
}
}
-pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: &Input) -> String {
+pub fn find_crate_name(sess: &Session, attrs: &[ast::Attribute], input: &Input) -> String {
let validate = |s: String, span: Option<Span>| {
validate_crate_name(sess, &s, span);
s
// the command line over one found in the #[crate_name] attribute. If we
// find both we ensure that they're the same later on as well.
let attr_crate_name =
- attr::find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
-
- if let Some(sess) = sess {
- if let Some(ref s) = sess.opts.crate_name {
- if let Some((attr, name)) = attr_crate_name {
- if name.as_str() != *s {
- let msg = format!(
- "`--crate-name` and `#[crate_name]` are \
- required to match, but `{}` != `{}`",
- s, name
- );
- sess.span_err(attr.span, &msg);
- }
+ sess.find_by_name(attrs, sym::crate_name).and_then(|at| at.value_str().map(|s| (at, s)));
+
+ if let Some(ref s) = sess.opts.crate_name {
+ if let Some((attr, name)) = attr_crate_name {
+ if name.as_str() != *s {
+ let msg = format!(
+ "`--crate-name` and `#[crate_name]` are \
+ required to match, but `{}` != `{}`",
+ s, name
+ );
+ sess.span_err(attr.span, &msg);
}
- return validate(s.clone(), None);
}
+ return validate(s.clone(), None);
}
if let Some((attr, s)) = attr_crate_name {
`{}` has a leading hyphen",
s
);
- if let Some(sess) = sess {
- sess.err(&msg);
- }
+ sess.err(&msg);
} else {
return validate(s.replace("-", "_"), None);
}
"rust_out".to_string()
}
-pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option<Span>) {
+pub fn validate_crate_name(sess: &Session, s: &str, sp: Option<Span>) {
let mut err_count = 0;
{
let mut say = |s: &str| {
- match (sp, sess) {
- (_, None) => panic!("{}", s),
- (Some(sp), Some(sess)) => sess.span_err(sp, s),
- (None, Some(sess)) => sess.err(s),
+ match sp {
+ Some(sp) => sess.span_err(sp, s),
+ None => sess.err(s),
}
err_count += 1;
};
}
if err_count > 0 {
- sess.unwrap().abort_if_errors();
+ sess.abort_if_errors();
}
}
use crate::parse::ParseSess;
use crate::search_paths::{PathKind, SearchPath};
+pub use rustc_ast::ast::Attribute;
+pub use rustc_ast::attr::MarkedAttrs;
pub use rustc_ast::crate_disambiguator::CrateDisambiguator;
use rustc_data_structures::flock;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId, ErrorReported};
use rustc_span::edition::Edition;
use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span};
-use rustc_span::{SourceFileHashAlgorithm, Symbol};
+use rustc_span::{sym, SourceFileHashAlgorithm, Symbol};
use rustc_target::asm::InlineAsmArch;
use rustc_target::spec::{CodeModel, PanicStrategy, RelocModel, RelroLevel};
use rustc_target::spec::{Target, TargetTriple, TlsModel};
/// Set of enabled features for the current target.
pub target_features: FxHashSet<Symbol>,
+
+ known_attrs: Lock<MarkedAttrs>,
+ used_attrs: Lock<MarkedAttrs>,
}
pub struct PerfStats {
// MemorySanitizer uses lifetimes to detect use of uninitialized stack variables.
|| self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY)
}
+
+ pub fn mark_attr_known(&self, attr: &Attribute) {
+ self.known_attrs.lock().mark(attr)
+ }
+
+ pub fn is_attr_known(&self, attr: &Attribute) -> bool {
+ self.known_attrs.lock().is_marked(attr)
+ }
+
+ pub fn mark_attr_used(&self, attr: &Attribute) {
+ self.used_attrs.lock().mark(attr)
+ }
+
+ pub fn is_attr_used(&self, attr: &Attribute) -> bool {
+ self.used_attrs.lock().is_marked(attr)
+ }
+
+ /// Returns `true` if the attribute's path matches the argument. If it matches, then the
+ /// attribute is marked as used.
+
+ /// Returns `true` if the attribute's path matches the argument. If it
+ /// matches, then the attribute is marked as used.
+ ///
+ /// This method should only be used by rustc, other tools can use
+ /// `Attribute::has_name` instead, because only rustc is supposed to report
+ /// the `unused_attributes` lint. (`MetaItem` and `NestedMetaItem` are
+ /// produced by lowering an `Attribute` and don't have identity, so they
+ /// only have the `has_name` method, and you need to mark the original
+ /// `Attribute` as used when necessary.)
+ pub fn check_name(&self, attr: &Attribute, name: Symbol) -> bool {
+ let matches = attr.has_name(name);
+ if matches {
+ self.mark_attr_used(attr);
+ }
+ matches
+ }
+
+ pub fn is_proc_macro_attr(&self, attr: &Attribute) -> bool {
+ [sym::proc_macro, sym::proc_macro_attribute, sym::proc_macro_derive]
+ .iter()
+ .any(|kind| self.check_name(attr, *kind))
+ }
+
+ pub fn contains_name(&self, attrs: &[Attribute], name: Symbol) -> bool {
+ attrs.iter().any(|item| self.check_name(item, name))
+ }
+
+ pub fn find_by_name<'a>(
+ &'a self,
+ attrs: &'a [Attribute],
+ name: Symbol,
+ ) -> Option<&'a Attribute> {
+ attrs.iter().find(|attr| self.check_name(attr, name))
+ }
+
+ pub fn filter_by_name<'a>(
+ &'a self,
+ attrs: &'a [Attribute],
+ name: Symbol,
+ ) -> impl Iterator<Item = &'a Attribute> {
+ attrs.iter().filter(move |attr| self.check_name(attr, name))
+ }
+
+ pub fn first_attr_value_str_by_name(
+ &self,
+ attrs: &[Attribute],
+ name: Symbol,
+ ) -> Option<Symbol> {
+ attrs.iter().find(|at| self.check_name(at, name)).and_then(|at| at.value_str())
+ }
}
fn default_emitter(
real_rust_source_base_dir,
asm_arch,
target_features: FxHashSet::default(),
+ known_attrs: Lock::new(MarkedAttrs::new()),
+ used_attrs: Lock::new(MarkedAttrs::new()),
};
validate_commandline_args_with_session_available(&sess);
Opaque,
}
-pub(crate) const NUM_TRANSPARENCIES: usize = 3;
-
impl ExpnId {
pub fn fresh(expn_data: Option<ExpnData>) -> Self {
HygieneData::with(|data| data.fresh_expn(expn_data))
HygieneData::with(|data| data.expn_data(data.outer_expn(self)).clone())
}
+ #[inline]
+ pub fn outer_mark(self) -> (ExpnId, Transparency) {
+ HygieneData::with(|data| data.outer_mark(self))
+ }
+
#[inline]
pub fn outer_mark_with_data(self) -> (ExpnId, Transparency, ExpnData) {
HygieneData::with(|data| {
/// The kind of this expansion - macro or compiler desugaring.
pub kind: ExpnKind,
/// The expansion that produced this expansion.
- #[stable_hasher(ignore)]
pub parent: ExpnId,
/// The location of the actual macro invocation or syntax sugar , e.g.
/// `let x = foo!();` or `if let Some(y) = x {}`
drop(expns);
expn_id
});
- return Ok(expn_id);
+ Ok(expn_id)
}
// Decodes `SyntaxContext`, using the provided `HygieneDecodeContext`
assert_eq!(dummy.dollar_crate_name, kw::Invalid);
});
- return Ok(new_ctxt);
+ Ok(new_ctxt)
}
pub fn num_syntax_ctxts() -> usize {
mode: ExpnDataEncodeMode,
e: &mut E,
) -> Result<(), E::Error> {
- if !context.serialized_expns.lock().contains(&expn) {
- context.latest_expns.lock().insert(expn);
- }
+ // Record the fact that we need to serialize the corresponding
+ // `ExpnData`
+ let needs_data = || {
+ if !context.serialized_expns.lock().contains(&expn) {
+ context.latest_expns.lock().insert(expn);
+ }
+ };
+
match mode {
- ExpnDataEncodeMode::IncrComp => expn.0.encode(e),
+ ExpnDataEncodeMode::IncrComp => {
+ // Always serialize the `ExpnData` in incr comp mode
+ needs_data();
+ expn.0.encode(e)
+ }
ExpnDataEncodeMode::Metadata => {
let data = expn.expn_data();
+ // We only need to serialize the ExpnData
+ // if it comes from this crate.
+ // We currently don't serialize any hygiene information data for
+ // proc-macro crates: see the `SpecializedEncoder<Span>` impl
+ // for crate metadata.
+ if data.krate == LOCAL_CRATE {
+ needs_data();
+ }
data.orig_id.expect("Missing orig_id").encode(e)?;
data.krate.encode(e)
}
use edition::Edition;
pub mod hygiene;
pub use hygiene::SyntaxContext;
+use hygiene::Transparency;
pub use hygiene::{DesugaringKind, ExpnData, ExpnId, ExpnKind, ForLoopLoc, MacroKind};
-use hygiene::{Transparency, NUM_TRANSPARENCIES};
pub mod def_id;
use def_id::{CrateNum, DefId, LOCAL_CRATE};
mod span_encoding;
}
}
+pub fn with_session_globals<R>(edition: Edition, f: impl FnOnce() -> R) -> R {
+ let session_globals = SessionGlobals::new(edition);
+ SESSION_GLOBALS.set(&session_globals, f)
+}
+
+pub fn with_default_session_globals<R>(f: impl FnOnce() -> R) -> R {
+ with_session_globals(edition::DEFAULT_EDITION, f)
+}
+
// If this ever becomes non thread-local, `decode_syntax_context`
// and `decode_expn_id` will need to be updated to handle concurrent
// deserialization.
TAG_NO_EXPANSION.hash_stable(ctx, hasher);
} else {
TAG_EXPANSION.hash_stable(ctx, hasher);
+ let (expn_id, transparency) = self.outer_mark();
+ expn_id.hash_stable(ctx, hasher);
+ transparency.hash_stable(ctx, hasher);
+ }
+ }
+}
- // Since the same expansion context is usually referenced many
- // times, we cache a stable hash of it and hash that instead of
- // recursing every time.
- thread_local! {
- static CACHE: RefCell<Vec<Option<[Option<u64>; NUM_TRANSPARENCIES]>>> = Default::default();
- }
+impl<CTX: HashStableContext> HashStable<CTX> for ExpnId {
+ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) {
+ // Since the same expansion context is usually referenced many
+ // times, we cache a stable hash of it and hash that instead of
+ // recursing every time.
+ thread_local! {
+ static CACHE: RefCell<Vec<Option<Fingerprint>>> = Default::default();
+ }
- let sub_hash: u64 = CACHE.with(|cache| {
- let (expn_id, transparency, _) = self.outer_mark_with_data();
- let index = expn_id.as_u32() as usize;
+ const TAG_ROOT: u8 = 0;
+ const TAG_NOT_ROOT: u8 = 1;
- if let Some(sub_hash_cache) = cache.borrow().get(index).copied().flatten() {
- if let Some(sub_hash) = sub_hash_cache[transparency as usize] {
- return sub_hash;
- }
- }
+ if *self == ExpnId::root() {
+ TAG_ROOT.hash_stable(ctx, hasher);
+ return;
+ }
- let new_len = index + 1;
+ TAG_NOT_ROOT.hash_stable(ctx, hasher);
+ let index = self.as_u32() as usize;
- let mut hasher = StableHasher::new();
- expn_id.expn_data().hash_stable(ctx, &mut hasher);
- transparency.hash_stable(ctx, &mut hasher);
+ let res = CACHE.with(|cache| cache.borrow().get(index).copied().flatten());
- let sub_hash: Fingerprint = hasher.finish();
- let sub_hash = sub_hash.to_smaller_hash();
+ if let Some(res) = res {
+ res.hash_stable(ctx, hasher);
+ } else {
+ let new_len = index + 1;
+ let mut sub_hasher = StableHasher::new();
+ self.expn_data().hash_stable(ctx, &mut sub_hasher);
+ let sub_hash: Fingerprint = sub_hasher.finish();
+
+ CACHE.with(|cache| {
let mut cache = cache.borrow_mut();
if cache.len() < new_len {
cache.resize(new_len, None);
}
- if let Some(mut sub_hash_cache) = cache[index] {
- sub_hash_cache[transparency as usize] = Some(sub_hash);
- } else {
- let mut sub_hash_cache = [None; NUM_TRANSPARENCIES];
- sub_hash_cache[transparency as usize] = Some(sub_hash);
- cache[index] = Some(sub_hash_cache);
- }
- sub_hash
+ cache[index].replace(sub_hash).expect_none("Cache slot was filled");
});
-
sub_hash.hash_stable(ctx, hasher);
}
}
use crate::SESSION_GLOBALS;
use crate::{BytePos, SpanData};
-use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::fx::FxIndexSet;
/// A compressed span.
///
#[derive(Default)]
pub struct SpanInterner {
- spans: FxHashMap<SpanData, u32>,
- span_data: Vec<SpanData>,
+ spans: FxIndexSet<SpanData>,
}
impl SpanInterner {
fn intern(&mut self, span_data: &SpanData) -> u32 {
- if let Some(index) = self.spans.get(span_data) {
- return *index;
- }
-
- let index = self.spans.len() as u32;
- self.span_data.push(*span_data);
- self.spans.insert(*span_data, index);
- index
+ let (index, _) = self.spans.insert_full(*span_data);
+ index as u32
}
#[inline]
fn get(&self, index: u32) -> &SpanData {
- &self.span_data[index as usize]
+ &self.spans[index as usize]
}
}
min_align_of,
min_align_of_val,
min_const_fn,
+ min_const_generics,
min_const_unsafe_fn,
min_specialization,
minnumf32,
not,
note,
object_safe_for_dispatch,
+ of,
offset,
omit_gdb_pretty_printer_section,
on,
}
// The `&'static str`s in this type actually point into the arena.
+//
+// The `FxHashMap`+`Vec` pair could be replaced by `FxIndexSet`, but #75278
+// found that to regress performance up to 2% in some cases. This might be
+// revisited after further improvements to `indexmap`.
#[derive(Default)]
pub struct Interner {
arena: DroplessArena,
let tcx = self.tcx;
let def_id = tcx.hir().local_def_id(hir_id);
for attr in tcx.get_attrs(def_id.to_def_id()).iter() {
- if attr.check_name(SYMBOL_NAME) {
+ if tcx.sess.check_name(attr, SYMBOL_NAME) {
// for now, can only use on monomorphic names
let instance = Instance::mono(tcx, def_id.to_def_id());
- let mangled = self.tcx.symbol_name(instance);
+ let mangled = tcx.symbol_name(instance);
tcx.sess.span_err(attr.span, &format!("symbol-name({})", mangled));
if let Ok(demangling) = rustc_demangle::try_demangle(mangled.name) {
tcx.sess.span_err(attr.span, &format!("demangling({})", demangling));
tcx.sess.span_err(attr.span, &format!("demangling-alt({:#})", demangling));
}
- } else if attr.check_name(DEF_PATH) {
+ } else if tcx.sess.check_name(attr, DEF_PATH) {
let path = tcx.def_path_str(def_id.to_def_id());
tcx.sess.span_err(attr.span, &format!("def-path({})", path));
}
}
pub fn span(&self) -> Span {
- self.span.clone()
+ self.span
}
pub fn reached_recursion_limit(&self) -> bool {
if let Ok(src) = self.tcx.sess.source_map().span_to_snippet(span) {
// Don't care about `&mut` because `DerefMut` is used less
// often and user will not expect autoderef happens.
- if src.starts_with("&") && !src.starts_with("&mut ") {
+ if src.starts_with('&') && !src.starts_with("&mut ") {
let derefs = "*".repeat(steps);
err.span_suggestion(
span,
) -> Result<Option<Self>, ErrorReported> {
let attrs = tcx.get_attrs(impl_def_id);
- let attr = if let Some(item) = attr::find_by_name(&attrs, sym::rustc_on_unimplemented) {
+ let attr = if let Some(item) = tcx.sess.find_by_name(&attrs, sym::rustc_on_unimplemented) {
item
} else {
return Ok(None);
use crate::infer::{InferCtxt, InferOk, TypeFreshener};
use crate::traits::error_reporting::InferCtxtExt;
use crate::traits::project::ProjectionCacheKeyExt;
-use rustc_ast::attr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::ErrorReported;
obligation
);
- // `previous_stack` stores a `TraitObligatiom`, while `obligation` is
+ // `previous_stack` stores a `TraitObligation`, while `obligation` is
// a `PredicateObligation`. These are distinct types, so we can't
// use any `Option` combinator method that would force them to be
// the same.
&mut self.intercrate_ambiguity_causes
{
let attrs = tcx.get_attrs(def_id);
- let attr = attr::find_by_name(&attrs, sym::rustc_reservation_impl);
+ let attr = tcx.sess.find_by_name(&attrs, sym::rustc_reservation_impl);
let value = attr.and_then(|a| a.value_str());
if let Some(value) = value {
debug!(
let predicates = self.tcx.predicates_of(adt_def.did).predicates;
let where_clauses: Vec<_> = predicates
- .into_iter()
+ .iter()
.map(|(wc, _)| wc.subst(self.tcx, bound_vars))
.filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner))
.collect();
phantom_data: adt_def.is_phantom_data(),
},
});
- return struct_datum;
+ struct_datum
}
fn fn_def_datum(
let predicates = self.tcx.predicates_defined_on(def_id).predicates;
let where_clauses: Vec<_> = predicates
- .into_iter()
+ .iter()
.map(|(wc, _)| wc.subst(self.tcx, &bound_vars))
.filter_map(|wc| LowerInto::<Option<chalk_ir::QuantifiedWhereClause<RustInterner<'tcx>>>>::lower_into(wc, &self.interner)).collect();
parameters[0].assert_ty_ref(&self.interner).could_match(&self.interner, &lowered_ty)
});
- let impls = matched_impls.map(|matched_impl| chalk_ir::ImplId(matched_impl)).collect();
+ let impls = matched_impls.map(chalk_ir::ImplId).collect();
impls
}
ty::AdtKind::Struct | ty::AdtKind::Union => None,
ty::AdtKind::Enum => {
let constraint = self.tcx.adt_sized_constraint(adt_def.did);
- if constraint.0.len() > 0 { unimplemented!() } else { Some(true) }
+ if !constraint.0.is_empty() { unimplemented!() } else { Some(true) }
}
},
_ => None,
ty::AdtKind::Struct | ty::AdtKind::Union => None,
ty::AdtKind::Enum => {
let constraint = self.tcx.adt_sized_constraint(adt_def.did);
- if constraint.0.len() > 0 { unimplemented!() } else { Some(true) }
+ if !constraint.0.is_empty() { unimplemented!() } else { Some(true) }
}
},
_ => None,
FnOnce => self.tcx.lang_items().fn_once_trait(),
Unsize => self.tcx.lang_items().unsize_trait(),
};
- def_id.map(|t| chalk_ir::TraitId(t))
+ def_id.map(chalk_ir::TraitId)
}
fn is_object_safe(&self, trait_id: chalk_ir::TraitId<RustInterner<'tcx>>) -> bool {
let bounds = tcx.predicates_of(def_id);
let predicates =
- util::elaborate_predicates(tcx, bounds.predicates.into_iter().map(|&(pred, _)| pred));
+ util::elaborate_predicates(tcx, bounds.predicates.iter().map(|&(pred, _)| pred));
let filtered_predicates = predicates.filter_map(|obligation| {
let pred = obligation.predicate;
//
// FIXME? Other potential candidate methods: `as_ref` and
// `as_mut`?
- .any(|a| a.check_name(sym::rustc_conversion_suggestion))
+ .any(|a| self.sess().check_name(a, sym::rustc_conversion_suggestion))
});
methods
let anon_b = self.tcx.anonymize_late_bound_regions(&b);
self.relate(anon_a.skip_binder(), anon_b.skip_binder())?;
- Ok(a.clone())
+ Ok(a)
}
}
//! types computed here.
use super::FnCtxt;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
struct InteriorVisitor<'a, 'tcx> {
fcx: &'a FnCtxt<'a, 'tcx>,
- types: FxHashMap<ty::GeneratorInteriorTypeCause<'tcx>, usize>,
+ types: FxIndexSet<ty::GeneratorInteriorTypeCause<'tcx>>,
region_scope_tree: &'tcx region::ScopeTree,
expr_count: usize,
kind: hir::GeneratorKind,
.span_note(yield_data.span, &*note)
.emit();
} else {
- // Map the type to the number of types added before it
- let entries = self.types.len();
+ // Insert the type into the ordered set.
let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree));
- self.types
- .entry(ty::GeneratorInteriorTypeCause {
- span: source_span,
- ty: &ty,
- scope_span,
- yield_span: yield_data.span,
- expr: expr.map(|e| e.hir_id),
- })
- .or_insert(entries);
+ self.types.insert(ty::GeneratorInteriorTypeCause {
+ span: source_span,
+ ty: &ty,
+ scope_span,
+ yield_span: yield_data.span,
+ expr: expr.map(|e| e.hir_id),
+ });
}
} else {
debug!(
let body = fcx.tcx.hir().body(body_id);
let mut visitor = InteriorVisitor {
fcx,
- types: FxHashMap::default(),
+ types: FxIndexSet::default(),
region_scope_tree: fcx.tcx.region_scope_tree(def_id),
expr_count: 0,
kind,
let region_expr_count = visitor.region_scope_tree.body_expr_count(body_id).unwrap();
assert_eq!(region_expr_count, visitor.expr_count);
- let mut types: Vec<_> = visitor.types.drain().collect();
-
- // Sort types by insertion order
- types.sort_by_key(|t| t.1);
+ // The types are already kept in insertion order.
+ let types = visitor.types;
// The types in the generator interior contain lifetimes local to the generator itself,
// which should not be exposed outside of the generator. Therefore, we replace these
let mut captured_tys = FxHashSet::default();
let type_causes: Vec<_> = types
.into_iter()
- .filter_map(|(mut cause, _)| {
+ .filter_map(|mut cause| {
// Erase regions and canonicalize late-bound regions to deduplicate as many types as we
// can.
let erased = fcx.tcx.erase_regions(&cause.ty);
let repr = def.repr;
if repr.packed() {
for attr in tcx.get_attrs(def.did).iter() {
- for r in attr::find_repr_attrs(&tcx.sess.parse_sess, attr) {
+ for r in attr::find_repr_attrs(&tcx.sess, attr) {
if let attr::ReprPacked(pack) = r {
if let Some(repr_pack) = repr.pack {
if pack as u64 != repr_pack.bytes() {
if vs.is_empty() {
let attributes = tcx.get_attrs(def_id.to_def_id());
- if let Some(attr) = attr::find_by_name(&attributes, sym::repr) {
+ if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) {
struct_span_err!(
tcx.sess,
attr.span,
tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
}
} else if !etc && !unmentioned_fields.is_empty() {
- unmentioned_err = Some(self.error_unmentioned_fields(pat.span, &unmentioned_fields));
+ unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields));
}
match (inexistent_fields_err, unmentioned_err) {
(Some(mut i), Some(mut u)) => {
if tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"This error indicates that a struct pattern attempted to \
- extract a non-existent field from a struct. Struct fields \
- are identified by the name used before the colon : so struct \
- patterns should resemble the declaration of the struct type \
- being matched.\n\n\
- If you are using shorthand field patterns but want to refer \
- to the struct field by a different name, you should rename \
- it explicitly.",
+ extract a non-existent field from a struct. Struct fields \
+ are identified by the name used before the colon : so struct \
+ patterns should resemble the declaration of the struct type \
+ being matched.\n\n\
+ If you are using shorthand field patterns but want to refer \
+ to the struct field by a different name, you should rename \
+ it explicitly.",
);
}
err
fn error_unmentioned_fields(
&self,
- span: Span,
+ pat: &Pat<'_>,
unmentioned_fields: &[Ident],
) -> DiagnosticBuilder<'tcx> {
let field_names = if unmentioned_fields.len() == 1 {
.join(", ");
format!("fields {}", fields)
};
- let mut diag = struct_span_err!(
+ let mut err = struct_span_err!(
self.tcx.sess,
- span,
+ pat.span,
E0027,
"pattern does not mention {}",
field_names
);
- diag.span_label(span, format!("missing {}", field_names));
- if self.tcx.sess.teach(&diag.get_code().unwrap()) {
- diag.note(
+ err.span_label(pat.span, format!("missing {}", field_names));
+ if self.tcx.sess.teach(&err.get_code().unwrap()) {
+ err.note(
"This error indicates that a pattern for a struct fails to specify a \
- sub-pattern for every one of the struct's fields. Ensure that each field \
- from the struct's definition is mentioned in the pattern, or use `..` to \
- ignore unwanted fields.",
+ sub-pattern for every one of the struct's fields. Ensure that each field \
+ from the struct's definition is mentioned in the pattern, or use `..` to \
+ ignore unwanted fields.",
);
}
- diag
+ err
}
fn check_pat_box(
// Gather up expressions we want to munge.
let mut exprs = vec![expr];
- loop {
- match exprs.last().unwrap().kind {
- hir::ExprKind::Field(ref expr, _)
- | hir::ExprKind::Index(ref expr, _)
- | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) => exprs.push(&expr),
- _ => break,
- }
+ while let hir::ExprKind::Field(ref expr, _)
+ | hir::ExprKind::Index(ref expr, _)
+ | hir::ExprKind::Unary(hir::UnOp::UnDeref, ref expr) = exprs.last().unwrap().kind
+ {
+ exprs.push(&expr);
}
debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs);
use crate::middle::resolve_lifetime as rl;
use rustc_ast::ast;
use rustc_ast::ast::MetaItemKind;
-use rustc_attr::{list_contains_name, mark_used, InlineAttr, OptimizeAttr};
+use rustc_attr::{list_contains_name, InlineAttr, OptimizeAttr};
use rustc_data_structures::captures::Captures;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
use rustc_errors::{struct_span_err, Applicability};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
// HACK(eddyb) this provides the correct generics when
// `feature(const_generics)` is enabled, so that const expressions
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
+ //
+ // Note that we do not supply the parent generics when using
+ // `feature(min_const_generics)`.
Some(parent_def_id.to_def_id())
} else {
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
/// A data structure with unique elements, which preserves order of insertion.
/// Preserving the order of insertion is important here so as not to break
/// compile-fail UI tests.
- // FIXME(eddyb) just use `IndexSet` from `indexmap`.
struct UniquePredicates<'tcx> {
- predicates: Vec<(ty::Predicate<'tcx>, Span)>,
- uniques: FxHashSet<(ty::Predicate<'tcx>, Span)>,
+ predicates: FxIndexSet<(ty::Predicate<'tcx>, Span)>,
}
impl<'tcx> UniquePredicates<'tcx> {
fn new() -> Self {
- UniquePredicates { predicates: vec![], uniques: FxHashSet::default() }
+ UniquePredicates { predicates: FxIndexSet::default() }
}
fn push(&mut self, value: (ty::Predicate<'tcx>, Span)) {
- if self.uniques.insert(value) {
- self.predicates.push(value);
- }
+ self.predicates.insert(value);
}
fn extend<I: IntoIterator<Item = (ty::Predicate<'tcx>, Span)>>(&mut self, iter: I) {
}))
}
- let mut predicates = predicates.predicates;
+ let mut predicates: Vec<_> = predicates.predicates.into_iter().collect();
// Subtle: before we store the predicates into the tcx, we
// sort them so that predicates like `T: Foo<Item=U>` come
let mut link_ordinal_span = None;
let mut no_sanitize_span = None;
for attr in attrs.iter() {
- if attr.check_name(sym::cold) {
+ if tcx.sess.check_name(attr, sym::cold) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::COLD;
- } else if attr.check_name(sym::rustc_allocator) {
+ } else if tcx.sess.check_name(attr, sym::rustc_allocator) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::ALLOCATOR;
- } else if attr.check_name(sym::unwind) {
+ } else if tcx.sess.check_name(attr, sym::unwind) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::UNWIND;
- } else if attr.check_name(sym::ffi_returns_twice) {
+ } else if tcx.sess.check_name(attr, sym::ffi_returns_twice) {
if tcx.is_foreign_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_RETURNS_TWICE;
} else {
)
.emit();
}
- } else if attr.check_name(sym::ffi_pure) {
+ } else if tcx.sess.check_name(attr, sym::ffi_pure) {
if tcx.is_foreign_item(id) {
- if attrs.iter().any(|a| a.check_name(sym::ffi_const)) {
+ if attrs.iter().any(|a| tcx.sess.check_name(a, sym::ffi_const)) {
// `#[ffi_const]` functions cannot be `#[ffi_pure]`
struct_span_err!(
tcx.sess,
)
.emit();
}
- } else if attr.check_name(sym::ffi_const) {
+ } else if tcx.sess.check_name(attr, sym::ffi_const) {
if tcx.is_foreign_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::FFI_CONST;
} else {
)
.emit();
}
- } else if attr.check_name(sym::rustc_allocator_nounwind) {
+ } else if tcx.sess.check_name(attr, sym::rustc_allocator_nounwind) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_ALLOCATOR_NOUNWIND;
- } else if attr.check_name(sym::naked) {
+ } else if tcx.sess.check_name(attr, sym::naked) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NAKED;
- } else if attr.check_name(sym::no_mangle) {
+ } else if tcx.sess.check_name(attr, sym::no_mangle) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::NO_MANGLE;
- } else if attr.check_name(sym::rustc_std_internal_symbol) {
+ } else if tcx.sess.check_name(attr, sym::rustc_std_internal_symbol) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
- } else if attr.check_name(sym::used) {
+ } else if tcx.sess.check_name(attr, sym::used) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED;
- } else if attr.check_name(sym::thread_local) {
+ } else if tcx.sess.check_name(attr, sym::thread_local) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL;
- } else if attr.check_name(sym::track_caller) {
+ } else if tcx.sess.check_name(attr, sym::track_caller) {
if tcx.is_closure(id) || tcx.fn_sig(id).abi() != abi::Abi::Rust {
struct_span_err!(tcx.sess, attr.span, E0737, "`#[track_caller]` requires Rust ABI")
.emit();
}
codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER;
- } else if attr.check_name(sym::export_name) {
+ } else if tcx.sess.check_name(attr, sym::export_name) {
if let Some(s) = attr.value_str() {
if s.as_str().contains('\0') {
// `#[export_name = ...]` will be converted to a null-terminated string,
}
codegen_fn_attrs.export_name = Some(s);
}
- } else if attr.check_name(sym::target_feature) {
+ } else if tcx.sess.check_name(attr, sym::target_feature) {
if !tcx.features().target_feature_11 {
check_target_feature_safe_fn(tcx, id, attr.span);
} else if let Some(local_id) = id.as_local() {
&supported_target_features,
&mut codegen_fn_attrs.target_features,
);
- } else if attr.check_name(sym::linkage) {
+ } else if tcx.sess.check_name(attr, sym::linkage) {
if let Some(val) = attr.value_str() {
codegen_fn_attrs.linkage = Some(linkage_by_name(tcx, id, &val.as_str()));
}
- } else if attr.check_name(sym::link_section) {
+ } else if tcx.sess.check_name(attr, sym::link_section) {
if let Some(val) = attr.value_str() {
if val.as_str().bytes().any(|b| b == 0) {
let msg = format!(
codegen_fn_attrs.link_section = Some(val);
}
}
- } else if attr.check_name(sym::link_name) {
+ } else if tcx.sess.check_name(attr, sym::link_name) {
codegen_fn_attrs.link_name = attr.value_str();
- } else if attr.check_name(sym::link_ordinal) {
+ } else if tcx.sess.check_name(attr, sym::link_ordinal) {
link_ordinal_span = Some(attr.span);
if let ordinal @ Some(_) = check_link_ordinal(tcx, attr) {
codegen_fn_attrs.link_ordinal = ordinal;
}
- } else if attr.check_name(sym::no_sanitize) {
+ } else if tcx.sess.check_name(attr, sym::no_sanitize) {
no_sanitize_span = Some(attr.span);
if let Some(list) = attr.meta_item_list() {
for item in list.iter() {
}
match attr.meta().map(|i| i.kind) {
Some(MetaItemKind::Word) => {
- mark_used(attr);
+ tcx.sess.mark_attr_used(attr);
InlineAttr::Hint
}
Some(MetaItemKind::List(ref items)) => {
- mark_used(attr);
+ tcx.sess.mark_attr_used(attr);
inline_span = Some(attr.span);
if items.len() != 1 {
struct_span_err!(
ia
}
Some(MetaItemKind::List(ref items)) => {
- mark_used(attr);
+ tcx.sess.mark_attr_used(attr);
inline_span = Some(attr.span);
if items.len() != 1 {
err(attr.span, "expected one argument");
if tcx.is_weak_lang_item(id) {
codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL;
}
- if let Some(name) = weak_lang_items::link_name(&attrs) {
+ let check_name = |attr, sym| tcx.sess.check_name(attr, sym);
+ if let Some(name) = weak_lang_items::link_name(check_name, &attrs) {
codegen_fn_attrs.export_name = Some(name);
codegen_fn_attrs.link_name = Some(name);
}
GenericParamKind::Type { default: Some(ref ty), .. } => icx.to_ty(ty),
GenericParamKind::Const { ty: ref hir_ty, .. } => {
let ty = icx.to_ty(hir_ty);
- let err = match ty.peel_refs().kind {
- ty::FnPtr(_) => Some("function pointers"),
- ty::RawPtr(_) => Some("raw pointers"),
- _ => None,
+ let err_ty_str;
+ let err = if tcx.features().min_const_generics {
+ match ty.kind {
+ ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None,
+ ty::FnPtr(_) => Some("function pointers"),
+ ty::RawPtr(_) => Some("raw pointers"),
+ _ => {
+ err_ty_str = format!("`{}`", ty);
+ Some(err_ty_str.as_str())
+ }
+ }
+ } else {
+ match ty.peel_refs().kind {
+ ty::FnPtr(_) => Some("function pointers"),
+ ty::RawPtr(_) => Some("raw pointers"),
+ _ => None,
+ }
};
if let Some(unsupported_type) = err {
- tcx.sess
- .struct_span_err(
- hir_ty.span,
- &format!(
- "using {} as const generic parameters is forbidden",
- unsupported_type
- ),
- )
- .emit();
+ let mut err = tcx.sess.struct_span_err(
+ hir_ty.span,
+ &format!(
+ "using {} as const generic parameters is forbidden",
+ unsupported_type
+ ),
+ );
+
+ if tcx.features().min_const_generics {
+ err.note("the only supported types are integers, `bool` and `char`")
+ .note("more complex types are supported with `#[feature(const_generics)]`").emit()
+ } else {
+ err.emit();
+ }
};
if traits::search_for_structural_match_violation(param.hir_id, param.span, tcx, ty)
.is_some()
}
for attr in it.attrs {
- if attr.check_name(sym::track_caller) {
+ if tcx.sess.check_name(attr, sym::track_caller) {
tcx.sess
.struct_span_err(
attr.span,
}
for attr in it.attrs {
- if attr.check_name(sym::track_caller) {
+ if tcx.sess.check_name(attr, sym::track_caller) {
tcx.sess
.struct_span_err(
attr.span,
self.tcx()
.sess
.delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT");
- return Err(());
+ Err(())
}
}
}
ty::Tuple(substs) => Ok(substs.len()),
_ => {
self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple");
- return Err(());
+ Err(())
}
}
}
use rustc_ast::ast::*;
use rustc_ast::attr;
-use rustc_ast::with_default_session_globals;
use rustc_span::symbol::{Ident, Symbol};
+use rustc_span::with_default_session_globals;
use rustc_span::DUMMY_SP;
fn word_cfg(s: &str) -> Cfg {
_ => None,
});
if let Some(lt) = lifetime.cloned() {
- if !lt.is_elided() {
- let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
- lt_substs.insert(lt_def_id.to_def_id(), lt.clean(cx));
- }
+ let lt_def_id = cx.tcx.hir().local_def_id(param.hir_id);
+ let cleaned = if !lt.is_elided() {
+ lt.clean(cx)
+ } else {
+ self::types::Lifetime::elided()
+ };
+ lt_substs.insert(lt_def_id.to_def_id(), cleaned);
}
indices.lifetimes += 1;
}
output: if output != Type::Tuple(Vec::new()) { Some(output) } else { None },
}
} else {
- let elide_lifetimes = self.args.iter().all(|arg| match arg {
- hir::GenericArg::Lifetime(lt) => lt.is_elided(),
- _ => true,
- });
GenericArgs::AngleBracketed {
args: self
.args
.iter()
- .filter_map(|arg| match arg {
- hir::GenericArg::Lifetime(lt) if !elide_lifetimes => {
- Some(GenericArg::Lifetime(lt.clean(cx)))
+ .map(|arg| match arg {
+ hir::GenericArg::Lifetime(lt) if !lt.is_elided() => {
+ GenericArg::Lifetime(lt.clean(cx))
}
- hir::GenericArg::Lifetime(_) => None,
- hir::GenericArg::Type(ty) => Some(GenericArg::Type(ty.clean(cx))),
- hir::GenericArg::Const(ct) => Some(GenericArg::Const(ct.clean(cx))),
+ hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()),
+ hir::GenericArg::Type(ty) => GenericArg::Type(ty.clean(cx)),
+ hir::GenericArg::Const(ct) => GenericArg::Const(ct.clean(cx)),
})
.collect(),
bindings: self.bindings.clean(cx),
use rustc_ast::ast::{self, AttrStyle};
use rustc_ast::attr;
-use rustc_ast::util::comments::strip_doc_comment_decoration;
+use rustc_ast::util::comments::beautify_doc_string;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def::Res;
.iter()
.filter_map(|attr| {
if let Some(value) = attr.doc_str() {
- let (value, mk_fragment): (_, fn(_, _, _) -> _) = if attr.is_doc_comment() {
- (strip_doc_comment_decoration(value), DocFragment::SugaredDoc)
+ let value = beautify_doc_string(value);
+ let mk_fragment: fn(_, _, _) -> _ = if attr.is_doc_comment() {
+ DocFragment::SugaredDoc
} else {
- (value.to_string(), DocFragment::RawDoc)
+ DocFragment::RawDoc
};
let line = doc_line;
pub fn statik() -> Lifetime {
Lifetime("'static".to_string())
}
+
+ pub fn elided() -> Lifetime {
+ Lifetime("'_".to_string())
+ }
}
#[derive(Clone, Debug)]
use crate::clean::blanket_impl::BlanketImplFinder;
use crate::clean::{
inline, Clean, Crate, Deprecation, ExternalCrate, FnDecl, FnRetTy, Generic, GenericArg,
- GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, MacroKind, Path,
- PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type, TypeBinding,
- TypeKind, Visibility, WherePredicate,
+ GenericArgs, GenericBound, Generics, GetDefId, ImportSource, Item, ItemEnum, Lifetime,
+ MacroKind, Path, PathSegment, Primitive, PrimitiveType, ResolvedPath, Span, Stability, Type,
+ TypeBinding, TypeKind, Visibility, WherePredicate,
};
use crate::core::DocContext;
let args: Vec<_> = substs
.iter()
.filter_map(|kind| match kind.unpack() {
- GenericArgKind::Lifetime(lt) => lt.clean(cx).map(GenericArg::Lifetime),
+ GenericArgKind::Lifetime(lt) => match lt {
+ ty::ReLateBound(_, ty::BrAnon(_)) => Some(GenericArg::Lifetime(Lifetime::elided())),
+ _ => lt.clean(cx).map(GenericArg::Lifetime),
+ },
GenericArgKind::Type(_) if skip_self => {
skip_self = false;
None
Res::Def(DefKind::TyAlias, i) => (i, TypeKind::Typedef),
Res::Def(DefKind::Enum, i) => (i, TypeKind::Enum),
Res::Def(DefKind::Trait, i) => (i, TypeKind::Trait),
+ Res::Def(DefKind::AssocTy | DefKind::AssocFn | DefKind::AssocConst, i) => {
+ (cx.tcx.parent(i).unwrap(), TypeKind::Trait)
+ }
Res::Def(DefKind::Struct, i) => (i, TypeKind::Struct),
Res::Def(DefKind::Union, i) => (i, TypeKind::Union),
Res::Def(DefKind::Mod, i) => (i, TypeKind::Module),
let sender = self.errors.clone().expect("can't write after closing");
rayon::spawn(move || {
fs::write(&path, contents).unwrap_or_else(|e| {
- sender
- .send(format!("\"{}\": {}", path.display(), e))
- .expect(&format!("failed to send error on \"{}\"", path.display()));
+ sender.send(format!("\"{}\": {}", path.display(), e)).unwrap_or_else(|_| {
+ panic!("failed to send error on \"{}\"", path.display())
+ })
});
});
- Ok(())
} else {
- Ok(try_err!(fs::write(&path, contents), path))
+ try_err!(fs::write(&path, contents), path);
}
+ Ok(())
}
}
-use rustc_ast::attr::with_session_globals;
use rustc_session::parse::ParseSess;
use rustc_span::edition::Edition;
+use rustc_span::with_session_globals;
use rustc_span::FileName;
use super::Classifier;
if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) {
if out.is_empty() {
out.push_str(&format!(
- "<h3 class=\"important\">Important traits for {}</h3>\
+ "<h3 class=\"notable\">Notable traits for {}</h3>\
<code class=\"content\">",
impl_.for_.print()
));
if !out.is_empty() {
out.insert_str(
0,
- "<span class=\"important-traits\"><span class=\"important-traits-tooltip\">ⓘ<div class='important-traits-tooltiptext'><span class=\"docblock\">"
+ "<span class=\"notable-traits\"><span class=\"notable-traits-tooltip\">ⓘ<div class='notable-traits-tooltiptext'><span class=\"docblock\">"
);
out.push_str("</code></span></div></span></span>");
});
}());
- onEachLazy(document.getElementsByClassName("important-traits"), function(e) {
+ onEachLazy(document.getElementsByClassName("notable-traits"), function(e) {
e.onclick = function() {
- this.getElementsByClassName('important-traits-tooltiptext')[0]
+ this.getElementsByClassName('notable-traits-tooltiptext')[0]
.classList.toggle("force-tooltip");
};
});
h3 {
font-size: 1.3em;
}
-h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.important),
+h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable),
h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) {
font-weight: 500;
margin: 20px 0 15px 0;
font-size: 0.8em;
}
-.content .methods > div:not(.important-traits) {
+.content .methods > div:not(.notable-traits) {
margin-left: 40px;
margin-bottom: 15px;
}
font-size: 20px;
}
-.important-traits-tooltip {
+.notable-traits-tooltip {
display: inline-block;
cursor: pointer;
}
-.important-traits:hover .important-traits-tooltiptext,
-.important-traits .important-traits-tooltiptext.force-tooltip {
+.notable-traits:hover .notable-traits-tooltiptext,
+.notable-traits .notable-traits-tooltiptext.force-tooltip {
display: inline-block;
}
-.important-traits .important-traits-tooltiptext {
+.notable-traits .notable-traits-tooltiptext {
display: none;
padding: 5px 3px 3px 3px;
border-radius: 6px;
border: 1px solid;
}
-.important-traits-tooltip::after {
+.notable-traits-tooltip::after {
/* The margin on the tooltip does not capture hover events,
this extends the area of hover enough so that mouse hover is not
lost when moving the mouse to the tooltip */
content: "\00a0\00a0\00a0";
}
-.important-traits .important, .important-traits .docblock {
+.notable-traits .notable, .notable-traits .docblock {
margin: 0;
}
-.important-traits .docblock code.content{
+.notable-traits .docblock code.content{
margin: 0;
padding: 0;
font-size: 20px;
font-size: 16px;
}
-.important-traits {
+.notable-traits {
cursor: pointer;
z-index: 2;
margin-left: 5px;
}
-h4 > .important-traits {
+h4 > .notable-traits {
position: absolute;
left: -44px;
top: 2px;
z-index: 1;
}
- h4 > .important-traits {
+ h4 > .notable-traits {
position: absolute;
left: -22px;
top: 24px;
margin-top: 0;
}
- .important-traits .important-traits-tooltiptext {
+ .notable-traits .notable-traits-tooltiptext {
left: 0;
top: 100%;
}
}
}
-h3.important {
+h3.notable {
margin: 0;
margin-bottom: 13px;
font-size: 19px;
border-color: transparent #314559 transparent transparent;
}
-.important-traits-tooltiptext {
+.notable-traits-tooltiptext {
background-color: #314559;
border-color: #5c6773;
}
border-color: transparent black transparent transparent;
}
-.important-traits-tooltiptext {
+.notable-traits-tooltiptext {
background-color: #111;
border-color: #777;
}
border-color: transparent black transparent transparent;
}
-.important-traits-tooltiptext {
+.notable-traits-tooltiptext {
background-color: #eee;
border-color: #999;
}
use crate::fold::{self, DocFolder};
use crate::passes::Pass;
-use rustc_ast::attr;
use rustc_span::symbol::sym;
use rustc_span::FileName;
use serde::Serialize;
return Some(i);
}
clean::ImplItem(ref impl_)
- if attr::contains_name(&i.attrs.other_attrs, sym::automatically_derived)
+ if i.attrs
+ .other_attrs
+ .iter()
+ .any(|item| item.has_name(sym::automatically_derived))
|| impl_.synthetic
|| impl_.blanket_impl.is_some() =>
{
use rustc_span::symbol::Symbol;
use rustc_span::DUMMY_SP;
+use std::cell::Cell;
use std::ops::Range;
use crate::clean::*;
cx: &'a DocContext<'tcx>,
// NOTE: this may not necessarily be a module in the current crate
mod_ids: Vec<DefId>,
+ /// This is used to store the kind of associated items,
+ /// because `clean` and the disambiguator code expect them to be different.
+ /// See the code for associated items on inherent impls for details.
+ kind_side_channel: Cell<Option<DefKind>>,
}
impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
fn new(cx: &'a DocContext<'tcx>) -> Self {
- LinkCollector { cx, mod_ids: Vec::new() }
+ LinkCollector { cx, mod_ids: Vec::new(), kind_side_channel: Cell::new(None) }
}
fn variant_field(
fn resolve(
&self,
path_str: &str,
- disambiguator: Option<&str>,
+ disambiguator: Option<Disambiguator>,
ns: Namespace,
current_item: &Option<String>,
parent_id: Option<DefId>,
return Ok((res, Some(path_str.to_owned())));
}
Res::Def(DefKind::Mod, _) => {
- // This resolved to a module, but if we were passed `type@`,
- // we want primitive types to take precedence instead.
- if disambiguator == Some("type") {
+ // This resolved to a module, but we want primitive types to take precedence instead.
+ if matches!(
+ disambiguator,
+ None | Some(Disambiguator::Namespace(Namespace::TypeNS))
+ ) {
if let Some(prim) = is_primitive(path_str, ns) {
if extra_fragment.is_some() {
return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive));
AnchorFailure::AssocConstant
}))
} else {
+ // HACK(jynelson): `clean` expects the type, not the associated item.
+ // but the disambiguator logic expects the associated item.
+ // Store the kind in a side channel so that only the disambiguator logic looks at it.
+ self.kind_side_channel.replace(Some(item.kind.as_def_kind()));
Ok((ty_res, Some(format!("{}.{}", out, item_name))))
}
} else {
AnchorFailure::Method
}))
} else {
- Ok((ty_res, Some(format!("{}.{}", kind, item_name))))
+ let res = Res::Def(item.kind.as_def_kind(), item.def_id);
+ Ok((res, Some(format!("{}.{}", kind, item_name))))
}
} else {
self.variant_field(path_str, current_item, module_id)
};
let resolved_self;
let mut path_str;
+ let disambiguator;
let (res, fragment) = {
- let mut kind = None;
- let mut disambiguator = None;
- path_str = if let Some(prefix) =
- ["struct@", "enum@", "type@", "trait@", "union@", "module@", "mod@"]
- .iter()
- .find(|p| link.starts_with(**p))
- {
- kind = Some(TypeNS);
- disambiguator = Some(&prefix[..prefix.len() - 1]);
- link.trim_start_matches(prefix)
- } else if let Some(prefix) =
- ["const@", "static@", "value@", "function@", "fn@", "method@"]
- .iter()
- .find(|p| link.starts_with(**p))
- {
- kind = Some(ValueNS);
- disambiguator = Some(&prefix[..prefix.len() - 1]);
- link.trim_start_matches(prefix)
- } else if link.ends_with("!()") {
- kind = Some(MacroNS);
- link.trim_end_matches("!()")
- } else if link.ends_with("()") {
- kind = Some(ValueNS);
- disambiguator = Some("fn");
- link.trim_end_matches("()")
- } else if link.starts_with("macro@") {
- kind = Some(MacroNS);
- disambiguator = Some("macro");
- link.trim_start_matches("macro@")
- } else if link.starts_with("derive@") {
- kind = Some(MacroNS);
- disambiguator = Some("derive");
- link.trim_start_matches("derive@")
- } else if link.ends_with('!') {
- kind = Some(MacroNS);
- disambiguator = Some("macro");
- link.trim_end_matches('!')
+ path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) {
+ disambiguator = Some(d);
+ path
} else {
- &link[..]
+ disambiguator = None;
+ &link
}
.trim();
}
}
- match kind {
+ match disambiguator.map(Disambiguator::ns) {
Some(ns @ ValueNS) => {
match self.resolve(
path_str,
} else {
debug!("intra-doc link to {} resolved to {:?}", path_str, res);
+ // Disallow e.g. linking to enums with `struct@`
+ if let Res::Def(kind, id) = res {
+ debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator);
+ match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) {
+ | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const)))
+ // NOTE: this allows 'method' to mean both normal functions and associated functions
+ // This can't cause ambiguity because both are in the same namespace.
+ | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn)))
+ // These are namespaces; allow anything in the namespace to match
+ | (_, Some(Disambiguator::Namespace(_)))
+ // If no disambiguator given, allow anything
+ | (_, None)
+ // All of these are valid, so do nothing
+ => {}
+ (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {}
+ (_, Some(Disambiguator::Kind(expected))) => {
+ // The resolved item did not match the disambiguator; give a better error than 'not found'
+ let msg = format!("incompatible link kind for `{}`", path_str);
+ report_diagnostic(cx, &msg, &item, &dox, link_range, |diag, sp| {
+ // HACK(jynelson): by looking at the source I saw the DefId we pass
+ // for `expected.descr()` doesn't matter, since it's not a crate
+ let note = format!("this link resolved to {} {}, which is not {} {}", kind.article(), kind.descr(id), expected.article(), expected.descr(id));
+ let suggestion = Disambiguator::display_for(kind, path_str);
+ let help_msg = format!("to link to the {}, use its disambiguator", kind.descr(id));
+ diag.note(¬e);
+ if let Some(sp) = sp {
+ diag.span_suggestion(sp, &help_msg, suggestion, Applicability::MaybeIncorrect);
+ } else {
+ diag.help(&format!("{}: {}", help_msg, suggestion));
+ }
+ });
+ continue;
+ }
+ }
+ }
+
// item can be non-local e.g. when using #[doc(primitive = "pointer")]
if let Some((src_id, dst_id)) = res
.opt_def_id()
}
}
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Disambiguator {
+ Kind(DefKind),
+ Namespace(Namespace),
+}
+
+impl Disambiguator {
+ /// (disambiguator, path_str)
+ fn from_str(link: &str) -> Result<(Self, &str), ()> {
+ use Disambiguator::{Kind, Namespace as NS};
+
+ let find_suffix = || {
+ let suffixes = [
+ ("!()", DefKind::Macro(MacroKind::Bang)),
+ ("()", DefKind::Fn),
+ ("!", DefKind::Macro(MacroKind::Bang)),
+ ];
+ for &(suffix, kind) in &suffixes {
+ if link.ends_with(suffix) {
+ return Ok((Kind(kind), link.trim_end_matches(suffix)));
+ }
+ }
+ Err(())
+ };
+
+ if let Some(idx) = link.find('@') {
+ let (prefix, rest) = link.split_at(idx);
+ let d = match prefix {
+ "struct" => Kind(DefKind::Struct),
+ "enum" => Kind(DefKind::Enum),
+ "trait" => Kind(DefKind::Trait),
+ "union" => Kind(DefKind::Union),
+ "module" | "mod" => Kind(DefKind::Mod),
+ "const" | "constant" => Kind(DefKind::Const),
+ "static" => Kind(DefKind::Static),
+ "function" | "fn" | "method" => Kind(DefKind::Fn),
+ "derive" => Kind(DefKind::Macro(MacroKind::Derive)),
+ "type" => NS(Namespace::TypeNS),
+ "value" => NS(Namespace::ValueNS),
+ "macro" => NS(Namespace::MacroNS),
+ _ => return find_suffix(),
+ };
+ Ok((d, &rest[1..]))
+ } else {
+ find_suffix()
+ }
+ }
+
+ fn display_for(kind: DefKind, path_str: &str) -> String {
+ if kind == DefKind::Macro(MacroKind::Bang) {
+ return format!("{}!", path_str);
+ } else if kind == DefKind::Fn || kind == DefKind::AssocFn {
+ return format!("{}()", path_str);
+ }
+ let prefix = match kind {
+ DefKind::Struct => "struct",
+ DefKind::Enum => "enum",
+ DefKind::Trait => "trait",
+ DefKind::Union => "union",
+ DefKind::Mod => "mod",
+ DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst => {
+ "const"
+ }
+ DefKind::Static => "static",
+ DefKind::Macro(MacroKind::Derive) => "derive",
+ // Now handle things that don't have a specific disambiguator
+ _ => match kind
+ .ns()
+ .expect("tried to calculate a disambiguator for a def without a namespace?")
+ {
+ Namespace::TypeNS => "type",
+ Namespace::ValueNS => "value",
+ Namespace::MacroNS => "macro",
+ },
+ };
+ format!("{}@{}", prefix, path_str)
+ }
+
+ fn ns(self) -> Namespace {
+ match self {
+ Self::Namespace(n) => n,
+ Self::Kind(k) => {
+ k.ns().expect("only DefKinds with a valid namespace can be disambiguators")
+ }
+ }
+ }
+}
+
/// Reports a diagnostic for an intra-doc link.
///
/// If no link range is provided, or the source span of the link cannot be determined, the span of
// Uses librustc_ast to parse the doctest and find if there's a main fn and the extern
// crate already is included.
let result = rustc_driver::catch_fatal_errors(|| {
- rustc_ast::with_session_globals(edition, || {
+ rustc_span::with_session_globals(edition, || {
use rustc_errors::emitter::EmitterWriter;
use rustc_errors::Handler;
use rustc_parse::maybe_new_parser_from_source_str;
// The collapse-docs pass won't combine sugared/raw doc attributes, or included files with
// anything else, this will combine them for us.
if let Some(doc) = attrs.collapsed_doc_value() {
- self.collector.set_position(attrs.span.unwrap_or(DUMMY_SP));
+ // Use the outermost invocation, so that doctest names come from where the docs were written.
+ let span = attrs
+ .span
+ .map(|span| span.ctxt().outer_expn().expansion_cause().unwrap_or(span))
+ .unwrap_or(DUMMY_SP);
+ self.collector.set_position(span);
markdown::find_testable_code(
&doc,
self.collector,
--- /dev/null
+// compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1
+// ignore-tidy-linelength
+
+#![crate_type = "rlib"]
+
+// Test that only one copy of `Iter::map` and `iter::repeat` are generated.
+
+fn unused<T>() -> u64 {
+ 42
+}
+
+fn foo<T>() {
+ let x = [1, 2, 3, std::mem::size_of::<T>()];
+ x.iter().map(|_| ());
+}
+
+//~ MONO_ITEM fn core::iter[0]::adapters[0]::{{impl}}[29]::new[0]<core::slice[0]::Iter[0]<usize>, pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.0[External]
+//~ MONO_ITEM fn core::iter[0]::traits[0]::iterator[0]::Iterator[0]::map[0]<core::slice[0]::Iter[0]<usize>, (), pr_75255::foo[0]::{{closure}}[0]<T>> @@ pr_75255-cgu.1[Internal]
+
+fn bar<T>() {
+ std::iter::repeat(unused::<T>);
+}
+
+//~ MONO_ITEM fn core::iter[0]::sources[0]::repeat[0]<fn() -> u64> @@ pr_75255-cgu.1[Internal]
+
+pub fn dispatch() {
+ foo::<String>();
+ foo::<Vec<String>>();
+
+ bar::<String>();
+ bar::<Vec<String>>();
+}
+
+// These are all the items that aren't relevant to the test.
+//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::mem[0]::size_of[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::mem[0]::size_of[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::add[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::is_null[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::offset[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_add[0]<u8> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_offset[0]<u8> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::non_null[0]::{{impl}}[3]::new_unchecked[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::ptr[0]::null[0]<u8> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::as_ptr[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::iter[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::len[0]<usize> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn pr_75255::dispatch[0] @@ pr_75255-cgu.1[External]
+//~ MONO_ITEM fn pr_75255::foo[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn pr_75255::foo[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn pr_75255::bar[0]<alloc::string[0]::String[0]> @@ pr_75255-cgu.1[Internal]
+//~ MONO_ITEM fn pr_75255::bar[0]<alloc::vec[0]::Vec[0]<alloc::string[0]::String[0]>> @@ pr_75255-cgu.1[Internal]
--- /dev/null
+// compile-flags: -O
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @test
+// CHECK-NEXT: start:
+// CHECK-NEXT: tail call void @ext_fn0()
+#[no_mangle]
+pub fn test() {
+ test_inner(Some(inner0));
+}
+
+fn test_inner(f_maybe: Option<fn()>) {
+ if let Some(f) = f_maybe {
+ f();
+ }
+}
+
+fn inner0() {
+ unsafe { ext_fn0() };
+}
+
+extern "C" {
+ fn ext_fn0();
+}
// We have to ignore android because of this issue:
// https://github.com/rust-lang/rust/issues/74847
// ignore-android
+//
+// We need to use inline assembly, so just use one platform
+// only-x86_64
// compile-flags:-g
// lldb-command:continue
+#![feature(asm)]
#![feature(naked_functions)]
#![feature(omit_gdb_pretty_printer_section)]
#![omit_gdb_pretty_printer_section]
}
#[naked]
-fn naked(x: usize, y: usize) {
- zzz(); // #break
+extern "C" fn naked(x: usize, y: usize) {
+ unsafe { asm!("ret"); } // #break
}
-
-fn zzz() { () }
// cdb-check:hash_set,d [...] : { size=15 } [Type: [...]::HashSet<u64, [...]>]
// cdb-check: [size] : 15 [Type: [...]]
// cdb-check: [capacity] : [...]
-// cdb-check: [[...]] [...] : 0 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 0 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 1 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 1 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 2 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 2 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 3 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 3 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 4 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 4 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 5 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 5 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 6 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 6 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 7 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 7 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 8 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 8 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 9 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 9 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 10 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 10 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 11 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 11 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 12 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 12 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 13 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 13 [Type: u64]
// cdb-command: dx hash_set,d
-// cdb-check: [[...]] [...] : 14 [Type: unsigned __int64]
+// cdb-check: [[...]] [...] : 14 [Type: u64]
// cdb-command: dx hash_map,d
// cdb-check:hash_map,d [...] : { size=15 } [Type: [...]::HashMap<u64, u64, [...]>]
+// ignore-endian-big
extern "C" {
static X: i32;
}
-
static Y: i32 = 42;
// EMIT_MIR const_promotion_extern_static.BAR.PromoteTemps.diff
+// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
-
static FOO: &[(Option<i32>, &[&str])] =
&[(None, &[]), (None, &["foo", "bar"]), (Some(42), &["meh", "mop", "möp"])];
+// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
-
// EMIT_MIR const_allocation2.main.ConstProp.after.mir
fn main() {
FOO;
+// ignore-endian-big
// EMIT_MIR_FOR_EACH_BIT_WIDTH
-
// EMIT_MIR const_allocation3.main.ConstProp.after.mir
fn main() {
FOO;
--- /dev/null
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/large_array_index.rs:4:11: 4:11
+ let _1: u8; // in scope 0 at $DIR/large_array_index.rs:6:9: 6:10
+ let mut _2: [u8; 5000]; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+ let _3: usize; // in scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+ let mut _4: usize; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+ let mut _5: bool; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+ scope 1 {
+ debug x => _1; // in scope 1 at $DIR/large_array_index.rs:6:9: 6:10
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/large_array_index.rs:6:9: 6:10
+ StorageLive(_2); // scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+ _2 = [const 0_u8; 5000]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+ // ty::Const
+ // + ty: u8
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/large_array_index.rs:6:18: 6:22
+ // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+ StorageLive(_3); // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+ _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00000002))
+ // mir::Constant
+ // + span: $DIR/large_array_index.rs:6:30: 6:31
+ // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
+ _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x00001388))
+ // mir::Constant
+ // + span: $DIR/large_array_index.rs:6:17: 6:32
+ // + literal: Const { ty: usize, val: Value(Scalar(0x00001388)) }
+- _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++ _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++ // ty::Const
++ // + ty: bool
++ // + val: Value(Scalar(0x01))
++ // mir::Constant
++ // + span: $DIR/large_array_index.rs:6:17: 6:32
++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++ // ty::Const
++ // + ty: bool
++ // + val: Value(Scalar(0x01))
++ // mir::Constant
++ // + span: $DIR/large_array_index.rs:6:17: 6:32
++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00001388))
++ // mir::Constant
++ // + span: $DIR/large_array_index.rs:6:17: 6:32
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00001388)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x00000002))
++ // mir::Constant
++ // + span: $DIR/large_array_index.rs:6:17: 6:32
++ // + literal: Const { ty: usize, val: Value(Scalar(0x00000002)) }
+ }
+
+ bb1: {
+ _1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+ StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33
+ StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33
+ _0 = const (); // scope 0 at $DIR/large_array_index.rs:4:11: 7:2
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/large_array_index.rs:4:11: 7:2
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:7:1: 7:2
+ return; // scope 0 at $DIR/large_array_index.rs:7:2: 7:2
+ }
+ }
+
--- /dev/null
+- // MIR for `main` before ConstProp
++ // MIR for `main` after ConstProp
+
+ fn main() -> () {
+ let mut _0: (); // return place in scope 0 at $DIR/large_array_index.rs:4:11: 4:11
+ let _1: u8; // in scope 0 at $DIR/large_array_index.rs:6:9: 6:10
+ let mut _2: [u8; 5000]; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+ let _3: usize; // in scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+ let mut _4: usize; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+ let mut _5: bool; // in scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+ scope 1 {
+ debug x => _1; // in scope 1 at $DIR/large_array_index.rs:6:9: 6:10
+ }
+
+ bb0: {
+ StorageLive(_1); // scope 0 at $DIR/large_array_index.rs:6:9: 6:10
+ StorageLive(_2); // scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+ _2 = [const 0_u8; 5000]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:29
+ // ty::Const
+ // + ty: u8
+ // + val: Value(Scalar(0x00))
+ // mir::Constant
+ // + span: $DIR/large_array_index.rs:6:18: 6:22
+ // + literal: Const { ty: u8, val: Value(Scalar(0x00)) }
+ StorageLive(_3); // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+ _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000000002))
+ // mir::Constant
+ // + span: $DIR/large_array_index.rs:6:30: 6:31
+ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
+ _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+ // ty::Const
+ // + ty: usize
+ // + val: Value(Scalar(0x0000000000001388))
+ // mir::Constant
+ // + span: $DIR/large_array_index.rs:6:17: 6:32
+ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000001388)) }
+- _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++ _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++ // ty::Const
++ // + ty: bool
++ // + val: Value(Scalar(0x01))
++ // mir::Constant
++ // + span: $DIR/large_array_index.rs:6:17: 6:32
++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
++ // ty::Const
++ // + ty: bool
++ // + val: Value(Scalar(0x01))
++ // mir::Constant
++ // + span: $DIR/large_array_index.rs:6:17: 6:32
++ // + literal: Const { ty: bool, val: Value(Scalar(0x01)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000001388))
++ // mir::Constant
++ // + span: $DIR/large_array_index.rs:6:17: 6:32
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000001388)) }
++ // ty::Const
++ // + ty: usize
++ // + val: Value(Scalar(0x0000000000000002))
++ // mir::Constant
++ // + span: $DIR/large_array_index.rs:6:17: 6:32
++ // + literal: Const { ty: usize, val: Value(Scalar(0x0000000000000002)) }
+ }
+
+ bb1: {
+ _1 = _2[_3]; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32
+ StorageDead(_3); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33
+ StorageDead(_2); // scope 0 at $DIR/large_array_index.rs:6:32: 6:33
+ _0 = const (); // scope 0 at $DIR/large_array_index.rs:4:11: 7:2
+ // ty::Const
+ // + ty: ()
+ // + val: Value(Scalar(<ZST>))
+ // mir::Constant
+ // + span: $DIR/large_array_index.rs:4:11: 7:2
+ // + literal: Const { ty: (), val: Value(Scalar(<ZST>)) }
+ StorageDead(_1); // scope 0 at $DIR/large_array_index.rs:7:1: 7:2
+ return; // scope 0 at $DIR/large_array_index.rs:7:2: 7:2
+ }
+ }
+
--- /dev/null
+// EMIT_MIR_FOR_EACH_BIT_WIDTH
+
+// EMIT_MIR large_array_index.main.ConstProp.diff
+fn main() {
+ // check that we don't propagate this, because it's too large
+ let x: u8 = [0_u8; 5000][2];
+}
// + ty: i32
// + val: Value(Scalar(0x0000002a))
// mir::Constant
-- // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
-+ // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
+ // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:18: 5:20
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002a)) }
// ty::Const
// + ty: i32
// + val: Value(Scalar(0x0000002b))
// mir::Constant
-- // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
-+ // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:17: 5:25
+ // + span: $DIR/mutable_variable_aggregate_mut_ref.rs:5:22: 5:24
// + literal: Const { ty: i32, val: Value(Scalar(0x0000002b)) }
StorageLive(_2); // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:9: 6:10
_2 = &mut _1; // scope 1 at $DIR/mutable_variable_aggregate_mut_ref.rs:6:13: 6:19
+// ignore-endian-big
// ignore-wasm32-bare compiled with panic=abort by default
// compile-flags: -Z mir-opt-level=3
// EMIT_MIR_FOR_EACH_BIT_WIDTH
#![feature(box_syntax)]
-
// EMIT_MIR inline_into_box_place.main.Inline.diff
fn main() {
let _x: Box<Vec<u32>> = box Vec::new();
--- /dev/null
+#[macro_export]
+macro_rules! attrs_on_struct {
+ ( $( #[$attr:meta] )* ) => {
+ $( #[$attr] )*
+ pub struct ExpandedStruct;
+ }
+}
+// edition:2018
+// aux-build:extern_macros.rs
// compile-flags:--test --test-args=--test-threads=1
// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR"
// check-pass
//! assert_eq!(1 + 1, 2);
//! ```
+extern crate extern_macros as macros;
+
+use macros::attrs_on_struct;
+
pub mod foo {
/// ```
/// ```
pub fn bar() {}
}
+
+attrs_on_struct! {
+ /// ```
+ /// assert!(true);
+ /// ```
+}
-running 2 tests
-test $DIR/doctest-output.rs - (line 5) ... ok
-test $DIR/doctest-output.rs - foo::bar (line 11) ... ok
+running 3 tests
+test $DIR/doctest-output.rs - (line 7) ... ok
+test $DIR/doctest-output.rs - ExpandedStruct (line 23) ... ok
+test $DIR/doctest-output.rs - foo::bar (line 17) ... ok
-test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
+test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
--- /dev/null
+#![deny(broken_intra_doc_links)]
+//~^ NOTE lint level is defined
+pub enum S {}
+
+macro_rules! m {
+ () => {};
+}
+
+static s: usize = 0;
+const c: usize = 0;
+
+trait T {}
+
+/// Link to [struct@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [mod@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [union@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [trait@S]
+//~^ ERROR incompatible link kind for `S`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [struct@T]
+//~^ ERROR incompatible link kind for `T`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [derive@m]
+//~^ ERROR incompatible link kind for `m`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [const@s]
+//~^ ERROR incompatible link kind for `s`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [static@c]
+//~^ ERROR incompatible link kind for `c`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [fn@c]
+//~^ ERROR incompatible link kind for `c`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [c()]
+//~^ ERROR incompatible link kind for `c`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+
+/// Link to [const@f]
+//~^ ERROR incompatible link kind for `f`
+//~| NOTE this link resolved
+//~| HELP use its disambiguator
+pub fn f() {}
--- /dev/null
+error: incompatible link kind for `S`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:14:14
+ |
+LL | /// Link to [struct@S]
+ | ^^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
+ |
+note: the lint level is defined here
+ --> $DIR/intra-links-disambiguator-mismatch.rs:1:9
+ |
+LL | #![deny(broken_intra_doc_links)]
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ = note: this link resolved to an enum, which is not a struct
+
+error: incompatible link kind for `S`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:19:14
+ |
+LL | /// Link to [mod@S]
+ | ^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
+ |
+ = note: this link resolved to an enum, which is not a module
+
+error: incompatible link kind for `S`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:24:14
+ |
+LL | /// Link to [union@S]
+ | ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
+ |
+ = note: this link resolved to an enum, which is not a union
+
+error: incompatible link kind for `S`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:29:14
+ |
+LL | /// Link to [trait@S]
+ | ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S`
+ |
+ = note: this link resolved to an enum, which is not a trait
+
+error: incompatible link kind for `T`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:34:14
+ |
+LL | /// Link to [struct@T]
+ | ^^^^^^^^ help: to link to the trait, use its disambiguator: `trait@T`
+ |
+ = note: this link resolved to a trait, which is not a struct
+
+error: incompatible link kind for `m`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:39:14
+ |
+LL | /// Link to [derive@m]
+ | ^^^^^^^^ help: to link to the macro, use its disambiguator: `m!`
+ |
+ = note: this link resolved to a macro, which is not a derive macro
+
+error: incompatible link kind for `s`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:44:14
+ |
+LL | /// Link to [const@s]
+ | ^^^^^^^ help: to link to the static, use its disambiguator: `static@s`
+ |
+ = note: this link resolved to a static, which is not a constant
+
+error: incompatible link kind for `c`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:49:14
+ |
+LL | /// Link to [static@c]
+ | ^^^^^^^^ help: to link to the constant, use its disambiguator: `const@c`
+ |
+ = note: this link resolved to a constant, which is not a static
+
+error: incompatible link kind for `c`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:54:14
+ |
+LL | /// Link to [fn@c]
+ | ^^^^ help: to link to the constant, use its disambiguator: `const@c`
+ |
+ = note: this link resolved to a constant, which is not a function
+
+error: incompatible link kind for `c`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:59:14
+ |
+LL | /// Link to [c()]
+ | ^^^ help: to link to the constant, use its disambiguator: `const@c`
+ |
+ = note: this link resolved to a constant, which is not a function
+
+error: incompatible link kind for `f`
+ --> $DIR/intra-links-disambiguator-mismatch.rs:64:14
+ |
+LL | /// Link to [const@f]
+ | ^^^^^^^ help: to link to the function, use its disambiguator: `f()`
+ |
+ = note: this link resolved to a function, which is not a constant
+
+error: aborting due to 11 previous errors
+
--- /dev/null
+#![crate_name = "bar"]
+
+pub struct Ref<'a>(&'a u32);
+
+pub fn test5(a: &u32) -> Ref {
+ Ref(a)
+}
+
+pub fn test6(a: &u32) -> Ref<'_> {
+ Ref(a)
+}
--- /dev/null
+// aux-build:elided-lifetime.rs
+//
+// rust-lang/rust#75225
+//
+// Since Rust 2018 we encourage writing out <'_> explicitly to make it clear
+// that borrowing is occuring. Make sure rustdoc is following the same idiom.
+
+#![crate_name = "foo"]
+
+pub struct Ref<'a>(&'a u32);
+type ARef<'a> = Ref<'a>;
+
+// @has foo/fn.test1.html
+// @matches - "Ref</a><'_>"
+pub fn test1(a: &u32) -> Ref {
+ Ref(a)
+}
+
+// @has foo/fn.test2.html
+// @matches - "Ref</a><'_>"
+pub fn test2(a: &u32) -> Ref<'_> {
+ Ref(a)
+}
+
+// @has foo/fn.test3.html
+// @matches - "Ref</a><'_>"
+pub fn test3(a: &u32) -> ARef {
+ Ref(a)
+}
+
+// @has foo/fn.test4.html
+// @matches - "Ref</a><'_>"
+pub fn test4(a: &u32) -> ARef<'_> {
+ Ref(a)
+}
+
+// Ensure external paths in inlined docs also display elided lifetime
+// @has foo/bar/fn.test5.html
+// @matches - "Ref</a><'_>"
+// @has foo/bar/fn.test6.html
+// @matches - "Ref</a><'_>"
+#[doc(inline)]
+pub extern crate bar;
pub struct MyString;
/// See also [char]
-// @has intra_link_prim_precedence/struct.MyString2.html '//a/@href' 'intra_link_prim_precedence/char/index.html'
+// @has intra_link_prim_precedence/struct.MyString2.html '//a/@href' 'https://doc.rust-lang.org/nightly/std/primitive.char.html'
pub struct MyString2;
+
+/// See also [crate::char] and [mod@char]
+// @has intra_link_prim_precedence/struct.MyString3.html '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'crate::char'
+// @has - '//*[@href="../intra_link_prim_precedence/char/index.html"]' 'mod@char'
+pub struct MyString3;
--- /dev/null
+// ignore-tidy-linelength
+#![deny(broken_intra_doc_links)]
+
+/// Link to [S::assoc_fn()]
+/// Link to [Default::default()]
+// @has intra_link_trait_item/struct.S.html '//*[@href="../intra_link_trait_item/struct.S.html#method.assoc_fn"]' 'S::assoc_fn()'
+// @has - '//*[@href="https://doc.rust-lang.org/nightly/core/default/trait.Default.html#tymethod.default"]' 'Default::default()'
+pub struct S;
+
+impl S {
+ pub fn assoc_fn() {}
+}
impl LateLintPass<'_> for $struct {
fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) {
$(
- if !attr::contains_name(&krate.item.attrs, $attr) {
+ if !cx.sess().contains_name(&krate.item.attrs, $attr) {
cx.lint(CRATE_NOT_OKAY, |lint| {
let msg = format!("crate is not marked with #![{}]", $attr);
lint.build(&msg).set_span(krate.item.span).emit()
impl<'tcx> LateLintPass<'tcx> for Pass {
fn check_crate(&mut self, cx: &LateContext, krate: &rustc_hir::Crate) {
- if !attr::contains_name(&krate.item.attrs, Symbol::intern("crate_okay")) {
+ if !cx.sess().contains_name(&krate.item.attrs, Symbol::intern("crate_okay")) {
cx.lint(CRATE_NOT_OKAY, |lint| {
lint.build("crate is not marked with #![crate_okay]")
.set_span(krate.item.span)
mod gravy;
pub fn main() {
- rustc_ast::with_default_session_globals(|| parse());
+ rustc_span::with_default_session_globals(|| parse());
assert_eq!(gravy::foo(), 10);
}
}
fn main() {
- rustc_ast::with_default_session_globals(|| run());
+ rustc_span::with_default_session_globals(|| run());
}
fn run() {
--- /dev/null
+// compile-flags: --target wasm32-unknown-unknown
+// needs-llvm-components: webassembly
+
+#![feature(no_core, lang_items, rustc_attrs)]
+#![no_core]
+
+#[rustc_builtin_macro]
+macro_rules! asm {
+ () => {};
+}
+#[lang = "sized"]
+trait Sized {}
+
+fn main() {
+ unsafe {
+ asm!("");
+ //~^ ERROR asm! is unsupported on this target
+ }
+}
--- /dev/null
+error[E0472]: asm! is unsupported on this target
+ --> $DIR/bad-arch.rs:16:9
+ |
+LL | asm!("");
+ | ^^^^^^^^^
+
+error: aborting due to previous error
+
--- /dev/null
+// check-pass
+
+use std::collections::{BTreeMap, HashMap};
+
+trait Map
+where
+ for<'a> &'a Self: IntoIterator<Item = (&'a Self::Key, &'a Self::Value)>,
+{
+ type Key;
+ type Value;
+}
+
+impl<K, V> Map for HashMap<K, V> {
+ type Key = K;
+ type Value = V;
+}
+
+impl<K, V> Map for BTreeMap<K, V> {
+ type Key = K;
+ type Value = V;
+}
+
+fn main() {}
LL | trait Trait<const T: ()> {}
| ^
|
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics)]` to the crate attributes to enable
+ = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+ = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
error: aborting due to previous error
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
| ^
|
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics)]` to the crate attributes to enable
+ = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+ = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
error: aborting due to 2 previous errors
--- /dev/null
+error: type parameters with a default must be trailing
+ --> $DIR/wrong-order.rs:5:10
+ |
+LL | struct A<T = u32, const N: usize> {
+ | ^
+ |
+ = note: using type defaults and const parameters in the same parameter list is currently not permitted
+
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/wrong-order.rs:2:27
+ |
+LL | #![cfg_attr(full, feature(const_generics))]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: aborting due to previous error; 1 warning emitted
+
--- /dev/null
+error: type parameters with a default must be trailing
+ --> $DIR/wrong-order.rs:5:10
+ |
+LL | struct A<T = u32, const N: usize> {
+ | ^
+ |
+ = note: using type defaults and const parameters in the same parameter list is currently not permitted
+
+error: aborting due to previous error
+
-#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
struct A<T = u32, const N: usize> {
//~^ ERROR type parameters with a default must be trailing
+++ /dev/null
-error: type parameters with a default must be trailing
- --> $DIR/wrong-order.rs:3:10
- |
-LL | struct A<T = u32, const N: usize> {
- | ^
- |
- = note: using type defaults and const parameters in the same parameter list is currently not permitted
-
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/wrong-order.rs:1:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: aborting due to previous error; 1 warning emitted
-
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-56445.rs:3:27
+ |
+LL | #![cfg_attr(full, feature(const_generics))]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0771]: use of non-static lifetime `'a` in const generic
+ --> $DIR/issue-56445.rs:9:26
+ |
+LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
+ | ^^
+ |
+ = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0771`.
--- /dev/null
+error[E0771]: use of non-static lifetime `'a` in const generic
+ --> $DIR/issue-56445.rs:9:26
+ |
+LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
+ | ^^
+ |
+ = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
+
+error: using `&'static str` as const generic parameters is forbidden
+ --> $DIR/issue-56445.rs:9:25
+ |
+LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
+ | ^^^^^^^
+ |
+ = note: the only supported types are integers, `bool` and `char`
+ = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0771`.
// Regression test for https://github.com/rust-lang/rust/issues/56445#issuecomment-518402995.
-
-#![feature(const_generics)]
-//~^ WARN: the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
#![crate_type = "lib"]
use std::marker::PhantomData;
struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
//~^ ERROR: use of non-static lifetime `'a` in const generic
+//[min]~| ERROR: using `&'static str` as const
impl Bug<'_, ""> {}
+++ /dev/null
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/issue-56445.rs:3:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error[E0771]: use of non-static lifetime `'a` in const generic
- --> $DIR/issue-56445.rs:9:26
- |
-LL | struct Bug<'a, const S: &'a str>(PhantomData<&'a ()>);
- | ^^
- |
- = note: for more information, see issue #74052 <https://github.com/rust-lang/rust/issues/74052>
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0771`.
LL | struct B<const I: u8>;
| ^
|
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics)]` to the crate attributes to enable
+ = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+ = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
error: aborting due to previous error
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-60818-struct-constructors.rs:3:27
+ |
+LL | #![cfg_attr(full, feature(const_generics))]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
// check-pass
-
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
struct Generic<const V: usize>;
+++ /dev/null
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/issue-60818-struct-constructors.rs:3:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-61336-1.rs:3:27
+ |
+LL | #![cfg_attr(full, feature(const_generics))]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
-
// build-pass
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; N]
+++ /dev/null
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/issue-61336-1.rs:1:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-61336-2.rs:2:27
+ |
+LL | #![cfg_attr(full, feature(const_generics))]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+ --> $DIR/issue-61336-2.rs:10:5
+ |
+LL | [x; { N }]
+ | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+ |
+ = note: the `Copy` trait is required because the repeated element will be copied
+help: consider restricting type parameter `T`
+ |
+LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+ --> $DIR/issue-61336-2.rs:10:5
+ |
+LL | [x; { N }]
+ | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+ |
+ = note: the `Copy` trait is required because the repeated element will be copied
+help: consider restricting type parameter `T`
+ |
+LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; { N }]
+++ /dev/null
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/issue-61336-2.rs:1:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
- --> $DIR/issue-61336-2.rs:9:5
- |
-LL | [x; { N }]
- | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
- |
- = note: the `Copy` trait is required because the repeated element will be copied
-help: consider restricting type parameter `T`
- |
-LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
- | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to previous error; 1 warning emitted
-
-For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-61336.rs:2:27
+ |
+LL | #![cfg_attr(full, feature(const_generics))]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+ --> $DIR/issue-61336.rs:10:5
+ |
+LL | [x; N]
+ | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+ |
+ = note: the `Copy` trait is required because the repeated element will be copied
+help: consider restricting type parameter `T`
+ |
+LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
--- /dev/null
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+ --> $DIR/issue-61336.rs:10:5
+ |
+LL | [x; N]
+ | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+ |
+ = note: the `Copy` trait is required because the repeated element will be copied
+help: consider restricting type parameter `T`
+ |
+LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
+ | ^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; N]
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-61422.rs:3:27
+ |
+LL | #![cfg_attr(full, feature(const_generics))]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
// check-pass
-
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
use std::mem;
+++ /dev/null
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/issue-61422.rs:3:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-61432.rs:3:27
+ |
+LL | #![cfg_attr(full, feature(const_generics))]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+warning: 1 warning emitted
+
// run-pass
-
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
fn promote<const N: i32>() {
// works:
+++ /dev/null
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/issue-61432.rs:3:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-warning: 1 warning emitted
-
--- /dev/null
+warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/issue-61747.rs:2:27
+ |
+LL | #![cfg_attr(full, feature(const_generics))]
+ | ^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
+
+error: constant expression depends on a generic parameter
+ --> $DIR/issue-61747.rs:8:23
+ |
+LL | fn successor() -> Const<{C + 1}> {
+ | ^^^^^^^^^^^^^^
+ |
+ = note: this may fail depending on what value the parameter takes
+
+error: aborting due to previous error; 1 warning emitted
+
--- /dev/null
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/issue-61747.rs:8:30
+ |
+LL | fn successor() -> Const<{C + 1}> {
+ | ^ non-trivial anonymous constants must not depend on the parameter `C`
+ |
+ = help: it is currently only allowed to use either `C` or `{ C }` as generic constants
+
+error: aborting due to previous error
+
-#![feature(const_generics)]
-//~^ WARN the feature `const_generics` is incomplete
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))] //[full]~WARN the feature `const_generics` is incomplete
+#![cfg_attr(min, feature(min_const_generics))]
struct Const<const N: usize>;
impl<const C: usize> Const<{C}> {
fn successor() -> Const<{C + 1}> {
- //~^ ERROR constant expression depends on a generic parameter
+ //[full]~^ ERROR constant expression depends on a generic parameter
+ //[min]~^^ ERROR generic parameters must not be used
Const
}
}
+++ /dev/null
-warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
- --> $DIR/issue-61747.rs:1:12
- |
-LL | #![feature(const_generics)]
- | ^^^^^^^^^^^^^^
- |
- = note: `#[warn(incomplete_features)]` on by default
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
-
-error: constant expression depends on a generic parameter
- --> $DIR/issue-61747.rs:7:23
- |
-LL | fn successor() -> Const<{C + 1}> {
- | ^^^^^^^^^^^^^^
- |
- = note: this may fail depending on what value the parameter takes
-
-error: aborting due to previous error; 1 warning emitted
-
--- /dev/null
+// check-pass
+#![feature(min_const_generics)]
+
+struct Foo<const N: usize>;
+
+impl<const N: usize> Foo<N> {
+ const VALUE: usize = N * 2;
+}
+
+trait Bar {
+ const ASSOC: usize;
+}
+
+impl<const N: usize> Bar for Foo<N> {
+ const ASSOC: usize = N * 3;
+}
+
+fn main() {}
--- /dev/null
+#![feature(min_const_generics)]
+
+fn test<const N: usize>() {}
+
+fn ok<const M: usize>() -> [u8; M] {
+ [0; { M }]
+}
+
+struct Break0<const N: usize>([u8; { N + 1 }]);
+//~^ ERROR generic parameters must not be used inside of non trivial constant values
+
+struct Break1<const N: usize>([u8; { { N } }]);
+//~^ ERROR generic parameters must not be used inside of non trivial constant values
+
+fn break2<const N: usize>() {
+ let _: [u8; N + 1];
+ //~^ ERROR generic parameters must not be used inside of non trivial constant values
+}
+
+fn break3<const N: usize>() {
+ let _ = [0; N + 1];
+ //~^ ERROR generic parameters must not be used inside of non trivial constant values
+}
+
+trait Foo {
+ const ASSOC: usize;
+}
+
+fn main() {}
--- /dev/null
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/complex-expression.rs:9:38
+ |
+LL | struct Break0<const N: usize>([u8; { N + 1 }]);
+ | ^ non-trivial anonymous constants must not depend on the parameter `N`
+ |
+ = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/complex-expression.rs:12:40
+ |
+LL | struct Break1<const N: usize>([u8; { { N } }]);
+ | ^ non-trivial anonymous constants must not depend on the parameter `N`
+ |
+ = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/complex-expression.rs:16:17
+ |
+LL | let _: [u8; N + 1];
+ | ^ non-trivial anonymous constants must not depend on the parameter `N`
+ |
+ = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: generic parameters must not be used inside of non trivial constant values
+ --> $DIR/complex-expression.rs:21:17
+ |
+LL | let _ = [0; N + 1];
+ | ^ non-trivial anonymous constants must not depend on the parameter `N`
+ |
+ = help: it is currently only allowed to use either `N` or `{ N }` as generic constants
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+#![feature(min_const_generics)]
+
+struct Foo<const N: [u8; 0]>;
+//~^ ERROR using `[u8; 0]` as const generic parameters is forbidden
+
+struct Bar<const N: ()>;
+//~^ ERROR using `()` as const generic parameters is forbidden
+
+#[derive(PartialEq, Eq)]
+struct No;
+
+struct Fez<const N: No>;
+//~^ ERROR using `No` as const generic parameters is forbidden
+
+struct Faz<const N: &'static u8>;
+//~^ ERROR using `&'static u8` as const generic parameters is forbidden
+
+fn main() {}
--- /dev/null
+error: using `[u8; 0]` as const generic parameters is forbidden
+ --> $DIR/complex-types.rs:3:21
+ |
+LL | struct Foo<const N: [u8; 0]>;
+ | ^^^^^^^
+ |
+ = note: the only supported types are integers, `bool` and `char`
+ = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `()` as const generic parameters is forbidden
+ --> $DIR/complex-types.rs:6:21
+ |
+LL | struct Bar<const N: ()>;
+ | ^^
+ |
+ = note: the only supported types are integers, `bool` and `char`
+ = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `No` as const generic parameters is forbidden
+ --> $DIR/complex-types.rs:12:21
+ |
+LL | struct Fez<const N: No>;
+ | ^^
+ |
+ = note: the only supported types are integers, `bool` and `char`
+ = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: using `&'static u8` as const generic parameters is forbidden
+ --> $DIR/complex-types.rs:15:21
+ |
+LL | struct Faz<const N: &'static u8>;
+ | ^^^^^^^^^^^
+ |
+ = note: the only supported types are integers, `bool` and `char`
+ = note: more complex types are supported with `#[feature(const_generics)]`
+
+error: aborting due to 4 previous errors
+
--- /dev/null
+fn test<const N: usize>() {}
+//~^ ERROR const generics are unstable
+
+fn main() {}
--- /dev/null
+error[E0658]: const generics are unstable
+ --> $DIR/feature-gate-min_const_generics.rs:1:15
+ |
+LL | fn test<const N: usize>() {}
+ | ^
+ |
+ = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+ = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0658`.
// run-pass
-#![feature(const_generics)]
+// revisions: full min
+#![cfg_attr(full, feature(const_generics))]
+#![cfg_attr(min, feature(min_const_generics))]
#![allow(incomplete_features)]
-#![feature(const_fn)]
struct Foo;
-// ignore-emscripten
+// only-x86_64
fn main() {
unsafe {
-// ignore-emscripten
+// only-x86_64
fn main() {
unsafe {
LL | struct ConstFn<const F: fn()>;
| ^
|
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics)]` to the crate attributes to enable
+ = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+ = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
error[E0658]: const generics are unstable
--> $DIR/feature-gate-const_generics-ptr.rs:5:23
LL | struct ConstPtr<const P: *const u32>;
| ^
|
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics)]` to the crate attributes to enable
+ = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+ = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
error: using function pointers as const generic parameters is forbidden
--> $DIR/feature-gate-const_generics-ptr.rs:1:25
LL | fn foo<const X: ()>() {}
| ^
|
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics)]` to the crate attributes to enable
+ = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+ = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
error[E0658]: const generics are unstable
--> $DIR/feature-gate-const_generics.rs:3:18
LL | struct Foo<const X: usize>([(); X]);
| ^
|
- = note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
- = help: add `#![feature(const_generics)]` to the crate attributes to enable
+ = note: see issue #74878 <https://github.com/rust-lang/rust/issues/74878> for more information
+ = help: add `#![feature(min_const_generics)]` to the crate attributes to enable
error: aborting due to 2 previous errors
--- /dev/null
+// Regression test for #59311. The test is taken from
+// rust-lang/rust/issues/71546#issuecomment-620638437
+// as they seem to have the same cause.
+
+// FIXME: It's not clear that this code ought to report
+// an error, but the regression test is here to ensure
+// that it does not ICE. See discussion on #74889 for details.
+
+pub trait T {
+ fn t<F: Fn()>(&self, _: F) {}
+}
+
+pub fn crash<V>(v: &V)
+where
+ for<'a> &'a V: T + 'static,
+{
+ v.t(|| {}); //~ ERROR: higher-ranked subtype error
+}
+
+fn main() {}
--- /dev/null
+error: higher-ranked subtype error
+ --> $DIR/issue-59311.rs:17:9
+ |
+LL | v.t(|| {});
+ | ^^^^^
+
+error: aborting due to previous error
+
fn main() {
for _i in 0..2 { //~ ERROR missing `in`
}
+ for _i in 0..2 { //~ ERROR missing `in`
+ }
}
fn main() {
for _i 0..2 { //~ ERROR missing `in`
}
+ for _i of 0..2 { //~ ERROR missing `in`
+ }
}
LL | for _i 0..2 {
| ^ help: try adding `in` here
-error: aborting due to previous error
+error: missing `in` in `for` loop
+ --> $DIR/issue-40782.rs:6:12
+ |
+LL | for _i of 0..2 {
+ | ^^ help: try using `in` here instead
+
+error: aborting due to 2 previous errors
--- /dev/null
+extern "C" {
+ fn lol() { //~ ERROR incorrect function inside `extern` block
+ println!("");
+ }
+}
+fn main() {}
--- /dev/null
+error: incorrect function inside `extern` block
+ --> $DIR/issue-75283.rs:2:8
+ |
+LL | extern "C" {
+ | ---------- `extern` blocks define existing foreign functions and functions inside of them cannot have a body
+LL | fn lol() {
+ | ________^^^___-
+ | | |
+ | | cannot have a body
+LL | | println!("");
+LL | | }
+ | |_____- help: remove the invalid body: `;`
+ |
+ = help: you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
+ = note: for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+
+error: aborting due to previous error
+
--- /dev/null
+// Regression test for #47429: short backtraces were not terminating correctly
+
+// compile-flags: -O
+// run-fail
+// check-run-results
+// exec-env:RUST_BACKTRACE=1
+
+// ignore-msvc see #62897 and `backtrace-debuginfo.rs` test
+// ignore-android FIXME #17520
+// ignore-cloudabi spawning processes is not supported
+// ignore-openbsd no support for libbacktrace without filename
+// ignore-wasm no panic or subprocess support
+// ignore-emscripten no panic or subprocess support
+// ignore-sgx no subprocess support
+
+fn main() {
+ panic!()
+}
--- /dev/null
+thread 'main' panicked at 'explicit panic', $DIR/issue-47429-short-backtraces.rs:17:5
+stack backtrace:
+ 0: std::panicking::begin_panic
+ 1: issue_47429_short_backtraces::main
+note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
--- /dev/null
+// build-pass
+// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+
+fn foo(f: impl Fn()) {
+ let x = |_: ()| ();
+
+ // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
+ // `x` that will differ for each instantiation despite polymorphisation of the varying
+ // argument.
+ let y = || x(());
+
+ // Consider `f` used in `foo`.
+ f();
+ // Use `y` so that it is visited in monomorphisation collection.
+ y();
+}
+
+fn entry_a() {
+ foo(|| ());
+}
+
+fn entry_b() {
+ foo(|| ());
+}
+
+fn main() {
+ entry_a();
+ entry_b();
+}
--- /dev/null
+// build-pass
+// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+
+fn foo(f: impl Fn()) {
+ // Mutate an upvar from `x` so that it implements `FnMut`.
+ let mut outer = 3;
+ let mut x = |_: ()| {
+ outer = 4;
+ ()
+ };
+
+ // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
+ // `x` that will differ for each instantiation despite polymorphisation of the varying
+ // argument.
+ let mut y = || x(());
+
+ // Consider `f` used in `foo`.
+ f();
+ // Use `y` so that it is visited in monomorphisation collection.
+ y();
+}
+
+fn entry_a() {
+ foo(|| ());
+}
+
+fn entry_b() {
+ foo(|| ());
+}
+
+fn main() {
+ entry_a();
+ entry_b();
+}
--- /dev/null
+// build-pass
+// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+
+fn foo(f: impl Fn()) {
+ // Move a non-copy type into `x` so that it implements `FnOnce`.
+ let outer = Vec::<u32>::new();
+ let x = move |_: ()| {
+ let inner = outer;
+ ()
+ };
+
+ // Don't use `f` in `y`, but refer to `x` so that the closure substs contain a reference to
+ // `x` that will differ for each instantiation despite polymorphisation of the varying
+ // argument.
+ let y = || x(());
+
+ // Consider `f` used in `foo`.
+ f();
+ // Use `y` so that it is visited in monomorphisation collection.
+ y();
+}
+
+fn entry_a() {
+ foo(|| ());
+}
+
+fn entry_b() {
+ foo(|| ());
+}
+
+fn main() {
+ entry_a();
+ entry_b();
+}
--- /dev/null
+// build-pass
+// compile-flags:-Zpolymorphize=on -Zsymbol-mangling-version=v0
+
+fn y_uses_f(f: impl Fn()) {
+ let x = |_: ()| ();
+
+ let y = || {
+ f();
+ x(());
+ };
+
+ f();
+ y();
+}
+
+fn x_uses_f(f: impl Fn()) {
+ let x = |_: ()| { f(); };
+
+ let y = || x(());
+
+ f();
+ y();
+}
+
+fn entry_a() {
+ x_uses_f(|| ());
+ y_uses_f(|| ());
+}
+
+fn entry_b() {
+ x_uses_f(|| ());
+ y_uses_f(|| ());
+}
+
+fn main() {
+ entry_a();
+ entry_b();
+}
--- /dev/null
+// build-fail
+// compile-flags: -Zpolymorphize=on
+#![crate_type = "lib"]
+#![feature(rustc_attrs)]
+
+fn foo<'a>(_: &'a ()) {}
+
+#[rustc_polymorphize_error]
+pub fn test<T>() {
+ //~^ ERROR item has unused generic parameters
+ foo(&());
+}
--- /dev/null
+error: item has unused generic parameters
+ --> $DIR/promoted-function-1.rs:9:8
+ |
+LL | pub fn test<T>() {
+ | ^^^^ - generic parameter `T` is unused
+
+error: aborting due to previous error
+
--- /dev/null
+// build-fail
+// compile-flags:-Zpolymorphize=on
+#![crate_type = "lib"]
+#![feature(lazy_normalization_consts, rustc_attrs)]
+//~^ WARN the feature `lazy_normalization_consts` is incomplete
+
+#[rustc_polymorphize_error]
+fn test<T>() {
+ //~^ ERROR item has unused generic parameters
+ let x = [0; 3 + 4];
+}
+
+pub fn caller() {
+ test::<String>();
+ test::<Vec<String>>();
+}
--- /dev/null
+warning: the feature `lazy_normalization_consts` is incomplete and may not be safe to use and/or cause compiler crashes
+ --> $DIR/promoted-function-2.rs:4:12
+ |
+LL | #![feature(lazy_normalization_consts, rustc_attrs)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `#[warn(incomplete_features)]` on by default
+ = note: see issue #72219 <https://github.com/rust-lang/rust/issues/72219> for more information
+
+error: item has unused generic parameters
+ --> $DIR/promoted-function-2.rs:8:4
+ |
+LL | fn test<T>() {
+ | ^^^^ - generic parameter `T` is unused
+
+error: aborting due to previous error; 1 warning emitted
+
// run-pass
+// compile-flags:-Zpolymorphize=on
+
fn fop<T>() {}
fn bar<T>() -> &'static fn() {
fn foo2<T: Default>() {
let _: T = Default::default();
(|| {
+ //~^ ERROR item has unused generic parameters
let call: extern "rust-call" fn(_, _) = Fn::call;
call(&|| {}, ());
//~^ ERROR item has unused generic parameters
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: item has unused generic parameters
- --> $DIR/unsized_cast.rs:21:15
+ --> $DIR/unsized_cast.rs:22:15
|
LL | fn foo2<T: Default>() {
| - generic parameter `T` is unused
LL | call(&|| {}, ());
| ^^^^^
-error: aborting due to 3 previous errors
+error: item has unused generic parameters
+ --> $DIR/unsized_cast.rs:19:5
+ |
+LL | fn foo2<T: Default>() {
+ | - generic parameter `T` is unused
+LL | let _: T = Default::default();
+LL | / (|| {
+LL | |
+LL | | let call: extern "rust-call" fn(_, _) = Fn::call;
+LL | | call(&|| {}, ());
+LL | |
+LL | | })();
+ | |______^
+
+error: aborting due to 4 previous errors
--- /dev/null
+// Regression test for issue #75062
+// Tests that we don't ICE on a privacy error for a fieldless tuple struct.
+
+mod foo {
+ struct Bar();
+}
+
+fn main() {
+ foo::Bar(); //~ ERROR tuple struct
+}
--- /dev/null
+error[E0603]: tuple struct `Bar` is private
+ --> $DIR/issue-75062-fieldless-tuple-struct.rs:9:10
+ |
+LL | foo::Bar();
+ | ^^^ private tuple struct
+ |
+note: the tuple struct `Bar` is defined here
+ --> $DIR/issue-75062-fieldless-tuple-struct.rs:5:5
+ |
+LL | struct Bar();
+ | ^^^^^^^^^^^^^
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0603`.
--- /dev/null
+// check-pass
+// compile-flags: -Z span-debug
+// aux-build:test-macros.rs
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
+#[macro_use]
+extern crate test_macros;
+
+print_bang! {
+
+/**
+*******
+* DOC *
+* DOC *
+* DOC *
+*******
+*/
+pub struct S;
+
+}
+
+fn main() {}
--- /dev/null
+PRINT-BANG INPUT (DISPLAY): /**
+*******
+* DOC *
+* DOC *
+* DOC *
+*******
+*/
+ pub struct S ;
+PRINT-BANG RE-COLLECTED (DISPLAY): #[doc = "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n"] pub struct S ;
+PRINT-BANG INPUT (DEBUG): TokenStream [
+ Punct {
+ ch: '#',
+ spacing: Alone,
+ span: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+ },
+ Group {
+ delimiter: Bracket,
+ stream: TokenStream [
+ Ident {
+ ident: "doc",
+ span: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+ },
+ Punct {
+ ch: '=',
+ spacing: Alone,
+ span: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+ },
+ Literal {
+ kind: Str,
+ symbol: "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n",
+ suffix: None,
+ span: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+ },
+ ],
+ span: $DIR/doc-comment-preserved.rs:13:1: 19:3 (#0),
+ },
+ Ident {
+ ident: "pub",
+ span: $DIR/doc-comment-preserved.rs:20:1: 20:4 (#0),
+ },
+ Ident {
+ ident: "struct",
+ span: $DIR/doc-comment-preserved.rs:20:5: 20:11 (#0),
+ },
+ Ident {
+ ident: "S",
+ span: $DIR/doc-comment-preserved.rs:20:12: 20:13 (#0),
+ },
+ Punct {
+ ch: ';',
+ spacing: Alone,
+ span: $DIR/doc-comment-preserved.rs:20:13: 20:14 (#0),
+ },
+]
// check-pass
// edition:2018
+// compile-flags: -Z span-debug
// aux-build:test-macros.rs
-// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
-// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
-// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
-// normalize-stdout-test "#\d+" -> "#CTXT"
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
#[macro_use]
extern crate test_macros;
PRINT-BANG INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:17:13: 17:19 (#3),
},
Ident {
ident: "M",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:17:20: 17:21 (#3),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:17:22: 17:28 (#3),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:17:30: 17:31 (#3),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:17:21: 17:32 (#3),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:17:32: 17:33 (#3),
},
]
PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:21:9: 21:15 (#3),
},
Ident {
ident: "A",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:21:16: 21:17 (#3),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:21:18: 21:24 (#3),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:21:26: 21:27 (#3),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:21:17: 21:28 (#3),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-57089.rs:21:28: 21:29 (#3),
},
]
// check-pass
// edition:2018
+// compile-flags: -Z span-debug
// aux-build:test-macros.rs
// aux-build:dollar-crate-external.rs
-// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
-// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
-// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
-// normalize-stdout-test "#\d+" -> "#CTXT"
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
#[macro_use]
extern crate test_macros;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:5: 19:11 (#3),
},
Ident {
ident: "A",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:12: 19:13 (#3),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "identity",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:14: 19:22 (#3),
},
Punct {
ch: '!',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:22: 19:23 (#3),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:24: 19:30 (#3),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:32: 19:33 (#3),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:23: 19:34 (#3),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:13: 19:35 (#3),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate-issue-62325.rs:19:35: 19:36 (#3),
},
]
PRINT-ATTR INPUT (DISPLAY): struct B(identity ! ($crate :: S)) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:5: 21:11 (#10),
},
Ident {
ident: "B",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:12: 21:13 (#10),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "identity",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:14: 21:22 (#10),
},
Punct {
ch: '!',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:22: 21:23 (#10),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:24: 21:30 (#10),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:32: 21:33 (#10),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:23: 21:34 (#10),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:13: 21:35 (#10),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:21:35: 21:36 (#10),
},
]
// check-pass
// edition:2018
+// compile-flags: -Z span-debug
// aux-build:test-macros.rs
// aux-build:dollar-crate-external.rs
-// Anonymize unstable non-dummy spans while still showing dummy spans `0..0`.
-// normalize-stdout-test "bytes\([^0]\w*\.\.(\w+)\)" -> "bytes(LO..$1)"
-// normalize-stdout-test "bytes\((\w+)\.\.[^0]\w*\)" -> "bytes($1..HI)"
-// normalize-stdout-test "#\d+" -> "#CTXT"
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
#[macro_use]
extern crate test_macros;
PRINT-BANG INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:20:17: 20:23 (#3),
},
Ident {
ident: "M",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:20:24: 20:25 (#3),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:20:26: 20:32 (#3),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:20:32: 20:34 (#3),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:20:32: 20:34 (#3),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:20:34: 20:35 (#3),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:20:25: 20:36 (#3),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:20:36: 20:37 (#3),
},
]
PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:24:13: 24:19 (#3),
},
Ident {
ident: "A",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:24:20: 24:21 (#3),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:24:22: 24:28 (#3),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:24:28: 24:30 (#3),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:24:28: 24:30 (#3),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:24:30: 24:31 (#3),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:24:21: 24:32 (#3),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:24:32: 24:33 (#3),
},
]
PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ;
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:27:13: 27:19 (#3),
},
Ident {
ident: "D",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:27:20: 27:21 (#3),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:27:22: 27:28 (#3),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:27:28: 27:30 (#3),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:27:28: 27:30 (#3),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:27:30: 27:31 (#3),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:27:21: 27:32 (#3),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/dollar-crate.rs:27:32: 27:33 (#3),
},
]
PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ;
PRINT-BANG INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:7:13: 7:19 (#13),
},
Ident {
ident: "M",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:7:20: 7:21 (#13),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:7:22: 7:28 (#13),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:7:30: 7:31 (#13),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:7:21: 7:32 (#13),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:7:32: 7:33 (#13),
},
]
PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:11:9: 11:15 (#13),
},
Ident {
ident: "A",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:11:16: 11:17 (#13),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:11:18: 11:24 (#13),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:11:26: 11:27 (#13),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:11:17: 11:28 (#13),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:11:28: 11:29 (#13),
},
]
PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ;
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:14:9: 14:15 (#13),
},
Ident {
ident: "D",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:14:16: 14:17 (#13),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [
Ident {
ident: "$crate",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:14:18: 14:24 (#13),
},
Punct {
ch: ':',
spacing: Joint,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13),
},
Ident {
ident: "S",
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:14:26: 14:27 (#13),
},
],
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:14:17: 14:28 (#13),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(LO..HI),
+ span: $DIR/auxiliary/dollar-crate-external.rs:14:28: 14:29 (#13),
},
]
// Check what token streams proc macros see when interpolated tokens are passed to them as input.
// check-pass
-// normalize-stdout-test "#\d+" -> "#CTXT"
+// edition:2018
// aux-build:test-macros.rs
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
#[macro_use]
extern crate test_macros;
stream: TokenStream [
Ident {
ident: "A",
- span: #CTXT bytes(445..446),
+ span: #0 bytes(503..504),
},
],
- span: #CTXT bytes(312..314),
+ span: #3 bytes(370..372),
},
]
PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ;
PRINT-ATTR INPUT (DEBUG): TokenStream [
Ident {
ident: "const",
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
Ident {
ident: "A",
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
Punct {
ch: ':',
spacing: Alone,
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
Ident {
ident: "u8",
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
Punct {
ch: '=',
spacing: Alone,
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
Literal {
kind: Integer,
symbol: "0",
suffix: None,
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
Punct {
ch: ';',
spacing: Alone,
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
]
PRINT-DERIVE INPUT (DISPLAY): struct A { }
PRINT-DERIVE INPUT (DEBUG): TokenStream [
Ident {
ident: "struct",
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
Ident {
ident: "A",
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
Group {
delimiter: Brace,
stream: TokenStream [],
- span: #CTXT bytes(0..0),
+ span: #0 bytes(0..0),
},
]
// aux-build:make-macro.rs
// aux-build:meta-macro.rs
// edition:2018
-// compile-flags: -Z span-debug -Z macro-backtrace
+// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene
// check-pass
-// normalize-stdout-test "#\d+" -> "#CTXT"
// normalize-stdout-test "\d+#" -> "0#"
//
// We don't care about symbol ids, so we set them all to 0
// in the stdout
+
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
extern crate meta_macro;
macro_rules! produce_it {
-Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT)
-Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:20:37: 20:43 (#CTXT) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:20:43: 20:45 (#CTXT) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:20:43: 20:45 (#CTXT) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:20:45: 20:50 (#CTXT) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:20:50: 20:51 (#CTXT) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:20:51: 20:53 (#CTXT) }]
-Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT) }]
+Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4)
+Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:23:37: 23:43 (#3) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#3) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#3) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:23:45: 23:50 (#3) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:50: 23:51 (#3) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:23:51: 23:53 (#3) }]
+Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }]
+#![feature /* 0#0 */(prelude_import)]
+// aux-build:make-macro.rs
+// aux-build:meta-macro.rs
+// edition:2018
+// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene
+// check-pass
+// normalize-stdout-test "\d+#" -> "0#"
+//
+// We don't care about symbol ids, so we set them all to 0
+// in the stdout
+
+#![no_std /* 0#0 */]
+#[prelude_import /* 0#1 */]
+use core /* 0#1 */::prelude /* 0#1 */::v1 /* 0#1 */::*;
+#[macro_use /* 0#1 */]
+extern crate core /* 0#1 */;
+#[macro_use /* 0#1 */]
+extern crate compiler_builtins /* 0#1 */;
+// Don't load unnecessary hygiene information from std
+extern crate std /* 0#0 */;
+
+extern crate meta_macro /* 0#0 */;
+
+macro_rules! produce_it
+ /*
+ 0#0
+ */ {
+ () =>
+ {
+ meta_macro :: print_def_site ! ($ crate :: dummy ! ()) ;
+ // `print_def_site!` will respan the `$crate` identifier
+ // with `Span::def_site()`. This should cause it to resolve
+ // relative to `meta_macro`, *not* `make_macro` (despite
+ // the fact that that `print_def_site` is produced by
+ // a `macro_rules!` macro in `make_macro`).
+ }
+}
+
+fn main /* 0#0 */() { }
+
+/*
+Expansions:
+0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root
+1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports)
+2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it")
+3: parent: ExpnId(2), call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site")
+4: parent: ExpnId(3), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy")
+
+SyntaxContexts:
+#0: parent: #0, outer_mark: (ExpnId(0), Opaque)
+#1: parent: #0, outer_mark: (ExpnId(1), Opaque)
+#2: parent: #0, outer_mark: (ExpnId(1), Transparent)
+#3: parent: #0, outer_mark: (ExpnId(2), SemiTransparent)
+#4: parent: #0, outer_mark: (ExpnId(3), Opaque)
+#5: parent: #3, outer_mark: (ExpnId(3), Transparent)
+#6: parent: #0, outer_mark: (ExpnId(3), SemiTransparent)
+#7: parent: #0, outer_mark: (ExpnId(4), Opaque)
+#8: parent: #4, outer_mark: (ExpnId(4), Transparent)
+#9: parent: #4, outer_mark: (ExpnId(4), SemiTransparent)
+*/
// aux-build:meta-macro.rs
// edition:2018
// compile-flags: -Z span-debug
-// normalize-stdout-test "#\d+" -> "#CTXT"
// run-pass
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
extern crate meta_macro;
fn main() {
-Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#CTXT)
+Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#3)
Input: TokenStream []
Respanned: TokenStream []
// aux-build:nested-macro-rules.rs
// aux-build:test-macros.rs
// compile-flags: -Z span-debug
-// normalize-stdout-test "#\d+" -> "#CTXT"
// edition:2018
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
extern crate nested_macro_rules;
extern crate test_macros;
stream: TokenStream [
Ident {
ident: "FirstStruct",
- span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#CTXT),
+ span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#5),
},
],
- span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#CTXT),
+ span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#4),
},
]
PRINT-BANG INPUT (DISPLAY): SecondStruct
stream: TokenStream [
Ident {
ident: "SecondStruct",
- span: $DIR/nested-macro-rules.rs:19:38: 19:50 (#CTXT),
+ span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#11),
},
],
- span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#CTXT),
+ span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#10),
},
]
// run-pass
// aux-build:test-macros.rs
// compile-flags: -Z span-debug
-// normalize-stdout-test "#\d+" -> "#CTXT"
// edition:2018
//
// Tests the pretty-printing behavior of inserting `NoDelim` groups
+#![no_std] // Don't load unnecessary hygiene information from std
+extern crate std;
+
extern crate test_macros;
use test_macros::print_bang_consume;
kind: Str,
symbol: "hi",
suffix: None,
- span: $DIR/nodelim-groups.rs:14:42: 14:46 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:42: 16:46 (#3),
},
Group {
delimiter: None,
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:18:16: 18:17 (#CTXT),
+ span: $DIR/nodelim-groups.rs:20:16: 20:17 (#0),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:18:18: 18:19 (#CTXT),
+ span: $DIR/nodelim-groups.rs:20:18: 20:19 (#0),
},
Group {
delimiter: Parenthesis,
kind: Integer,
symbol: "25",
suffix: None,
- span: $DIR/nodelim-groups.rs:18:21: 18:23 (#CTXT),
+ span: $DIR/nodelim-groups.rs:20:21: 20:23 (#0),
},
],
- span: $DIR/nodelim-groups.rs:18:20: 18:24 (#CTXT),
+ span: $DIR/nodelim-groups.rs:20:20: 20:24 (#0),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:18:25: 18:26 (#CTXT),
+ span: $DIR/nodelim-groups.rs:20:25: 20:26 (#0),
},
Literal {
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:18:27: 18:28 (#CTXT),
+ span: $DIR/nodelim-groups.rs:20:27: 20:28 (#0),
},
],
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#3),
},
Group {
delimiter: Parenthesis,
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:14:53: 14:54 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:53: 16:54 (#3),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:14:55: 14:56 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:55: 16:56 (#3),
},
Literal {
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:14:57: 14:58 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:57: 16:58 (#3),
},
],
- span: $DIR/nodelim-groups.rs:14:52: 14:59 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:52: 16:59 (#3),
},
]
PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1)
kind: Str,
symbol: "hi",
suffix: None,
- span: $DIR/nodelim-groups.rs:14:42: 14:46 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:42: 16:46 (#8),
},
Group {
delimiter: None,
kind: Str,
symbol: "hello",
suffix: None,
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
Punct {
ch: '.',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
Ident {
ident: "len",
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
Literal {
kind: Str,
symbol: "world",
suffix: None,
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
Punct {
ch: '.',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
Ident {
ident: "len",
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
Group {
delimiter: Parenthesis,
stream: TokenStream [],
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
],
- span: $DIR/nodelim-groups.rs:14:47: 14:51 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8),
},
Group {
delimiter: Parenthesis,
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:14:53: 14:54 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:53: 16:54 (#8),
},
Punct {
ch: '+',
spacing: Alone,
- span: $DIR/nodelim-groups.rs:14:55: 14:56 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:55: 16:56 (#8),
},
Literal {
kind: Integer,
symbol: "1",
suffix: None,
- span: $DIR/nodelim-groups.rs:14:57: 14:58 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:57: 16:58 (#8),
},
],
- span: $DIR/nodelim-groups.rs:14:52: 14:59 (#CTXT),
+ span: $DIR/nodelim-groups.rs:16:52: 16:59 (#8),
},
]
-error[E0391]: cycle detected when computing layout of `std::option::Option<S>`
+error[E0391]: cycle detected when computing layout of `S`
|
- = note: ...which requires computing layout of `S`...
- = note: ...which again requires computing layout of `std::option::Option<S>`, completing the cycle
+ = note: ...which requires computing layout of `std::option::Option<S>`...
+ = note: ...which again requires computing layout of `S`, completing the cycle
note: cycle used when optimizing MIR for `main`
--> $DIR/issue-26548-recursion-via-normalize.rs:15:1
|
#![allow(non_camel_case_types)]
// ignore-emscripten
+// ignore-endian-big behavior of simd_bitmask is endian-specific
// Test that the simd_bitmask intrinsic produces correct results.
#![allow(non_camel_case_types)]
// ignore-emscripten
-// ignore-mips behavior of simd_select_bitmask is endian-specific
-// ignore-mips64 behavior of simd_select_bitmask is endian-specific
-// ignore-powerpc behavior of simd_select_bitmask is endian-specific
-// ignore-powerpc64 behavior of simd_select_bitmask is endian-specific
+// ignore-endian-big behavior of simd_select_bitmask is endian-specific
// Test that the simd_select intrinsics produces correct results.
use if_chain::if_chain;
use itertools::Itertools;
use rustc_ast::ast::{AttrKind, Attribute};
+use rustc_ast::token::CommentKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
}
}
-/// Cleanup documentation decoration (`///` and such).
+/// Cleanup documentation decoration.
///
/// We can't use `rustc_ast::attr::AttributeMethods::with_desugared_doc` or
/// `rustc_ast::parse::lexer::comments::strip_doc_comment_decoration` because we
/// the spans but this function is inspired from the later.
#[allow(clippy::cast_possible_truncation)]
#[must_use]
-pub fn strip_doc_comment_decoration(comment: &str, span: Span) -> (String, Vec<(usize, Span)>) {
+pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: Span) -> (String, Vec<(usize, Span)>) {
// one-line comments lose their prefix
- const ONELINERS: &[&str] = &["///!", "///", "//!", "//"];
- for prefix in ONELINERS {
- if comment.starts_with(*prefix) {
- let doc = &comment[prefix.len()..];
- let mut doc = doc.to_owned();
- doc.push('\n');
- return (
- doc.to_owned(),
- vec![(doc.len(), span.with_lo(span.lo() + BytePos(prefix.len() as u32)))],
- );
- }
+ if comment_kind == CommentKind::Line {
+ let mut doc = doc.to_owned();
+ doc.push('\n');
+ let len = doc.len();
+ // +3 skips the opening delimiter
+ return (doc, vec![(len, span.with_lo(span.lo() + BytePos(3)))]);
}
- if comment.starts_with("/*") {
- let doc = &comment[3..comment.len() - 2];
- let mut sizes = vec![];
- let mut contains_initial_stars = false;
- for line in doc.lines() {
- let offset = line.as_ptr() as usize - comment.as_ptr() as usize;
- debug_assert_eq!(offset as u32 as usize, offset);
- contains_initial_stars |= line.trim_start().starts_with('*');
- // +1 for the newline
- sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(offset as u32))));
- }
- if !contains_initial_stars {
- return (doc.to_string(), sizes);
- }
- // remove the initial '*'s if any
- let mut no_stars = String::with_capacity(doc.len());
- for line in doc.lines() {
- let mut chars = line.chars();
- while let Some(c) = chars.next() {
- if c.is_whitespace() {
- no_stars.push(c);
- } else {
- no_stars.push(if c == '*' { ' ' } else { c });
- break;
- }
+ let mut sizes = vec![];
+ let mut contains_initial_stars = false;
+ for line in doc.lines() {
+ let offset = line.as_ptr() as usize - doc.as_ptr() as usize;
+ debug_assert_eq!(offset as u32 as usize, offset);
+ contains_initial_stars |= line.trim_start().starts_with('*');
+ // +1 adds the newline, +3 skips the opening delimiter
+ sizes.push((line.len() + 1, span.with_lo(span.lo() + BytePos(3 + offset as u32))));
+ }
+ if !contains_initial_stars {
+ return (doc.to_string(), sizes);
+ }
+ // remove the initial '*'s if any
+ let mut no_stars = String::with_capacity(doc.len());
+ for line in doc.lines() {
+ let mut chars = line.chars();
+ while let Some(c) = chars.next() {
+ if c.is_whitespace() {
+ no_stars.push(c);
+ } else {
+ no_stars.push(if c == '*' { ' ' } else { c });
+ break;
}
- no_stars.push_str(chars.as_str());
- no_stars.push('\n');
}
- return (no_stars, sizes);
+ no_stars.push_str(chars.as_str());
+ no_stars.push('\n');
}
- panic!("not a doc-comment: {}", comment);
+ (no_stars, sizes)
}
#[derive(Copy, Clone)]
let mut spans = vec![];
for attr in attrs {
- if let AttrKind::DocComment(ref comment) = attr.kind {
- let comment = comment.to_string();
- let (comment, current_spans) = strip_doc_comment_decoration(&comment, attr.span);
+ if let AttrKind::DocComment(comment_kind, comment) = attr.kind {
+ let (comment, current_spans) = strip_doc_comment_decoration(&comment.as_str(), comment_kind, attr.span);
spans.extend_from_slice(¤t_spans);
doc.push_str(&comment);
} else if attr.has_name(sym!(doc)) {
return;
}
if cx.access_levels.is_exported(item.hir_id)
- && !is_proc_macro(&item.attrs)
+ && !is_proc_macro(cx.sess(), &item.attrs)
&& attr_by_name(&item.attrs, "no_mangle").is_none()
{
check_must_use_candidate(
let fn_header_span = item.span.with_hi(sig.decl.output.span().hi());
check_needless_must_use(cx, &sig.decl, item.hir_id, item.span, fn_header_span, attr);
} else if cx.access_levels.is_exported(item.hir_id)
- && !is_proc_macro(&item.attrs)
+ && !is_proc_macro(cx.sess(), &item.attrs)
&& trait_ref_of_method(cx, item.hir_id).is_none()
{
check_must_use_candidate(
let body = cx.tcx.hir().body(eid);
Self::check_raw_ptr(cx, sig.header.unsafety, &sig.decl, body, item.hir_id);
- if attr.is_none() && cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(&item.attrs) {
+ if attr.is_none() && cx.access_levels.is_exported(item.hir_id) && !is_proc_macro(cx.sess(), &item.attrs) {
check_must_use_candidate(
cx,
&sig.decl,
"this seems like a manual implementation of the non-exhaustive pattern",
|diag| {
if_chain! {
- if !attr::contains_name(&item.attrs, sym!(non_exhaustive));
+ if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive)));
let header_span = cx.sess.source_map().span_until_char(item.span, '{');
if let Some(snippet) = snippet_opt(cx, header_span);
then {
"this seems like a manual implementation of the non-exhaustive pattern",
|diag| {
if_chain! {
- if !attr::contains_name(&item.attrs, sym!(non_exhaustive));
+ if !item.attrs.iter().any(|attr| attr.has_name(sym!(non_exhaustive)));
let header_span = find_header_span(cx, item, data);
if let Some(snippet) = snippet_opt(cx, header_span);
then {
use rustc_ast::ast::{
Arm, AssocItem, AssocItemKind, Attribute, Block, FnDecl, Item, ItemKind, Local, MacCall, Pat, PatKind,
};
-use rustc_ast::attr;
use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_middle::lint::in_external_macro;
}
fn do_check(lint: &mut NonExpressiveNames, cx: &EarlyContext<'_>, attrs: &[Attribute], decl: &FnDecl, blk: &Block) {
- if !attr::contains_name(attrs, sym!(test)) {
+ if !attrs.iter().any(|attr| attr.has_name(sym!(test))) {
let mut visitor = SimilarNamesLocalVisitor {
names: Vec::new(),
cx,
impl TabsInDocComments {
fn warn_if_tabs_in_doc(cx: &EarlyContext<'_>, attr: &ast::Attribute) {
- if let ast::AttrKind::DocComment(comment) = attr.kind {
+ if let ast::AttrKind::DocComment(_, comment) = attr.kind {
let comment = comment.as_str();
for (lo, hi) in get_chunks_of_tabs(&comment) {
+ // +3 skips the opening delimiter
let new_span = Span::new(
- attr.span.lo() + BytePos(lo),
- attr.span.lo() + BytePos(hi),
+ attr.span.lo() + BytePos(3 + lo),
+ attr.span.lo() + BytePos(3 + hi),
attr.span.ctxt(),
);
span_lint_and_sugg(
use AttrKind::*;
l.style == r.style
&& match (&l.kind, &r.kind) {
- (DocComment(l), DocComment(r)) => l == r,
+ (DocComment(l1, l2), DocComment(r1, r2)) => l1 == r1 && l2 == r2,
(Normal(l), Normal(r)) => eq_path(&l.path, &r.path) && eq_mac_args(&l.args, &r.args),
_ => false,
}
use rustc_ast::ast;
-use rustc_ast::expand::is_proc_macro_attr;
use rustc_errors::Applicability;
use rustc_session::Session;
use std::str::FromStr;
/// Return true if the attributes contain any of `proc_macro`,
/// `proc_macro_derive` or `proc_macro_attribute`, false otherwise
-pub fn is_proc_macro(attrs: &[ast::Attribute]) -> bool {
- attrs.iter().any(is_proc_macro_attr)
+pub fn is_proc_macro(sess: &Session, attrs: &[ast::Attribute]) -> bool {
+ attrs.iter().any(|attr| sess.is_proc_macro_attr(attr))
}
/// Checks for the `#[automatically_derived]` attribute all `#[derive]`d
/// implementations have.
pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool {
- attr::contains_name(attrs, sym!(automatically_derived))
+ attrs.iter().any(|attr| attr.has_name(sym!(automatically_derived)))
}
/// Remove blocks around an expression.
-error: this operation will panic at runtime
- --> $DIR/indexing_slicing_index.rs:11:5
- |
-LL | x[4]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
- | ^^^^ index out of bounds: the len is 4 but the index is 4
- |
- = note: `#[deny(unconditional_panic)]` on by default
-
-error: this operation will panic at runtime
- --> $DIR/indexing_slicing_index.rs:12:5
- |
-LL | x[1 << 3]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
- | ^^^^^^^^^ index out of bounds: the len is 4 but the index is 8
-
-error: this operation will panic at runtime
- --> $DIR/indexing_slicing_index.rs:27:5
- |
-LL | x[N]; // Ok, let rustc's `const_err` lint handle `usize` indexing on arrays.
- | ^^^^ index out of bounds: the len is 4 but the index is 15
-
error: indexing may panic.
--> $DIR/indexing_slicing_index.rs:10:5
|
|
= help: Consider using `.get(n)` or `.get_mut(n)` instead
-error: aborting due to 10 previous errors
+error: aborting due to 7 previous errors
}
/// Configuration for compiletest
-#[derive(Clone)]
+#[derive(Debug, Clone)]
pub struct Config {
/// `true` to to overwrite stderr/stdout files instead of complaining about changes in output.
pub bless: bool,
name == util::get_pointer_width(&self.target) || // pointer width
name == self.stage_id.split('-').next().unwrap() || // stage
(self.target != self.host && name == "cross-compile") ||
+ (name == "endian-big" && util::is_big_endian(&self.target)) ||
(self.remote_test_client.is_some() && name == "remote") ||
match self.compare_mode {
Some(CompareMode::Nll) => name == "compare-mode-nll",
emit_metadata: EmitMetadata,
allow_unused: AllowUnused,
) -> Command {
- let is_rustdoc = self.is_rustdoc();
+ let is_aux = input_file.components().map(|c| c.as_os_str()).any(|c| c == "auxiliary");
+ let is_rustdoc = self.is_rustdoc() && !is_aux;
let mut rustc = if !is_rustdoc {
Command::new(&self.config.rustc_path)
} else {
}
fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String {
- let before = self.get_mir_dump_dir().join(before);
- let after = self.get_mir_dump_dir().join(after);
+ let to_full_path = |path: PathBuf| {
+ let full = self.get_mir_dump_dir().join(&path);
+ if !full.exists() {
+ panic!(
+ "the mir dump file for {} does not exist (requested in {})",
+ path.display(),
+ self.testpaths.file.display(),
+ );
+ }
+ full
+ };
+ let before = to_full_path(before);
+ let after = to_full_path(after);
debug!("comparing the contents of: {} with {}", before.display(), after.display());
let before = fs::read_to_string(before).unwrap();
let after = fs::read_to_string(after).unwrap();
}
}
+#[derive(Debug)]
enum TargetLocation {
ThisFile(PathBuf),
ThisDirectory(PathBuf),
pub const TSAN_SUPPORTED_TARGETS: &'static [&'static str] =
&["aarch64-unknown-linux-gnu", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu"];
+const BIG_ENDIAN: &'static [&'static str] = &[
+ "armebv7r",
+ "mips",
+ "mips64",
+ "mipsisa32r6",
+ "mipsisa64r6",
+ "powerpc",
+ "powerpc64",
+ "s390x",
+ "sparc",
+ "sparc64",
+ "sparcv9",
+];
+
pub fn matches_os(triple: &str, name: &str) -> bool {
// For the wasm32 bare target we ignore anything also ignored on emscripten
// and then we also recognize `wasm32-bare` as the os for the target
panic!("Cannot determine Architecture from triple");
}
+/// Determine the endianness from `triple`
+pub fn is_big_endian(triple: &str) -> bool {
+ let triple_arch = triple.split('-').next().unwrap();
+ BIG_ENDIAN.contains(&triple_arch)
+}
+
pub fn matches_env(triple: &str, name: &str) -> bool {
if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false }
}
#![feature(rustc_private)]
-extern crate rustc_ast;
extern crate rustc_driver;
extern crate rustc_span;
fn main() {
rustc_driver::init_env_logger("RUST_LOG");
let (format, dst) = parse_args();
- let result = rustc_ast::with_default_session_globals(move || main_with_result(format, &dst));
+ let result = rustc_span::with_default_session_globals(move || main_with_result(format, &dst));
if let Err(e) = result {
panic!("{}", e.to_string());
}
-Subproject commit 55bdb3174653039f47362742f8dc941bfc086e8f
+Subproject commit cf633d0e897c065381b7b7d14984830176caf8b2
LABELS = {
'miri': ['A-miri', 'C-bug'],
'rls': ['A-rls', 'C-bug'],
- 'rustfmt': ['C-bug'],
+ 'rustfmt': ['A-rustfmt', 'C-bug'],
'book': ['C-bug'],
'nomicon': ['C-bug'],
'reference': ['C-bug'],
];
// Some error codes don't have any tests apparently...
-const IGNORE_EXPLANATION_CHECK: &[&str] =
- &["E0570", "E0601", "E0602", "E0639", "E0729", "E0749", "E0750"];
+const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0639", "E0729"];
fn check_error_code_explanation(
f: &str,
//! We have two separate encoding schemes: a skiplist-like approach, and a
//! compressed bitset. The datasets we consider mostly use the skiplist (it's
//! smaller) but the lowercase and uppercase sets are sufficiently sparse for
-//! the bitset to be worthwhile -- for those sets the biset is a 2x size win.
+//! the bitset to be worthwhile -- for those sets the bitset is a 2x size win.
//! Since the bitset is also faster, this seems an obvious choice. (As a
//! historical note, the bitset was also the prior implementation, so its
//! relative complexity had already been paid).