From: bors Date: Sun, 9 Aug 2020 18:19:34 +0000 (+0000) Subject: Auto merge of #75137 - Aaron1011:fix/hygiene-skip-expndata, r=petrochenkov X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=39e593ab14c53fda63c3f2756716c5ad3cbb6465;hp=ef49032297b90e7010b08db04d569dd8a5f0a8f2;p=rust.git Auto merge of #75137 - Aaron1011:fix/hygiene-skip-expndata, r=petrochenkov Don't serialize ExpnData for foreign crates When we encode an ExpnId into the crate metadata, we write out the CrateNum of the crate that 'owns' the corresponding `ExpnData`, which is later used to decode the `ExpnData` from its owning crate. However, we current serialize the `ExpnData` for all `ExpnIds` that we serialize, even if the `ExpnData` was already serialized into a foreign crate. This commit skips encoding this kind of `ExpnData`, which should hopefully speed up metadata encoding and reduce the total metadata size. --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86f60349c67..a19cca9071f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -575,6 +575,7 @@ jobs: CACHE_DOMAIN: ci-caches-gha.rust-lang.org if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'" strategy: + fail-fast: false matrix: include: - name: aarch64-gnu diff --git a/Cargo.lock b/Cargo.lock index d4f4ec7f6f0..57e7079dfb2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -137,12 +137,6 @@ dependencies = [ "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" @@ -766,7 +760,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0", + "autocfg", "cfg-if", "lazy_static", ] @@ -1245,11 +1239,11 @@ dependencies = [ [[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", @@ -2079,7 +2073,7 @@ version = "0.9.54" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1024c0a59774200a555087a6da3f253a9095a5f344e353b212ac4c8b8e450986" dependencies = [ - "autocfg 1.0.0", + "autocfg", "cc", "libc", "openssl-src", @@ -3201,7 +3195,6 @@ dependencies = [ "rustc_macros", "rustc_serialize", "rustc_span", - "scoped-tls", "smallvec 1.4.0", "tracing", ] @@ -4925,7 +4918,7 @@ dependencies = [ "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", diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 98c7ac3f2ef..518ac11b5a0 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -164,25 +164,34 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl AllocRef for Global { #[inline] - fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result { - unsafe { - let size = layout.size(); - if size == 0 { - Ok(MemoryBlock { ptr: layout.dangling(), size: 0 }) - } else { - let raw_ptr = match init { - AllocInit::Uninitialized => alloc(layout), - AllocInit::Zeroed => alloc_zeroed(layout), - }; - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; - Ok(MemoryBlock { ptr, size }) - } - } + fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + let size = layout.size(); + let ptr = if size == 0 { + layout.dangling() + } else { + // SAFETY: `layout` is non-zero in size, + unsafe { NonNull::new(alloc(layout)).ok_or(AllocErr)? } + }; + Ok(NonNull::slice_from_raw_parts(ptr, size)) + } + + #[inline] + fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + let size = layout.size(); + let ptr = if size == 0 { + layout.dangling() + } else { + // SAFETY: `layout` is non-zero in size, + unsafe { NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr)? } + }; + Ok(NonNull::slice_from_raw_parts(ptr, size)) } #[inline] unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { + // SAFETY: `layout` is non-zero in size, + // other conditions must be upheld by the caller unsafe { dealloc(ptr.as_ptr(), layout) } } } @@ -193,38 +202,59 @@ unsafe fn grow( ptr: NonNull, layout: Layout, new_size: usize, - placement: ReallocPlacement, - init: AllocInit, - ) -> Result { - let size = layout.size(); + ) -> Result, AllocErr> { debug_assert!( - new_size >= size, - "`new_size` must be greater than or equal to `memory.size()`" + new_size >= layout.size(), + "`new_size` must be greater than or equal to `layout.size()`" ); - if size == new_size { - return Ok(MemoryBlock { ptr, size }); + // SAFETY: `new_size` must be non-zero, which is checked in the match expression. + // Other conditions must be upheld by the caller + unsafe { + match layout.size() { + old_size if old_size == new_size => { + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + } + 0 => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())), + old_size => { + // `realloc` probably checks for `new_size > size` or something similar. + intrinsics::assume(new_size > old_size); + let raw_ptr = realloc(ptr.as_ptr(), layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + } + } } + } - match placement { - ReallocPlacement::InPlace => Err(AllocErr), - ReallocPlacement::MayMove if layout.size() == 0 => { - let new_layout = - unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; - self.alloc(new_layout, init) - } - ReallocPlacement::MayMove => { - // `realloc` probably checks for `new_size > size` or something similar. - let ptr = unsafe { - intrinsics::assume(new_size > size); - realloc(ptr.as_ptr(), layout, new_size) - }; - let memory = - MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }; - unsafe { - init.init_offset(memory, size); + #[inline] + unsafe fn grow_zeroed( + &mut self, + ptr: NonNull, + layout: Layout, + new_size: usize, + ) -> Result, AllocErr> { + debug_assert!( + new_size >= layout.size(), + "`new_size` must be greater than or equal to `layout.size()`" + ); + + // SAFETY: `new_size` must be non-zero, which is checked in the match expression. + // Other conditions must be upheld by the caller + unsafe { + match layout.size() { + old_size if old_size == new_size => { + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + } + 0 => self.alloc_zeroed(Layout::from_size_align_unchecked(new_size, layout.align())), + old_size => { + // `realloc` probably checks for `new_size > size` or something similar. + intrinsics::assume(new_size > old_size); + let raw_ptr = realloc(ptr.as_ptr(), layout, new_size); + raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) } - Ok(memory) } } } @@ -235,35 +265,34 @@ unsafe fn shrink( ptr: NonNull, layout: Layout, new_size: usize, - placement: ReallocPlacement, - ) -> Result { - let size = layout.size(); + ) -> Result, AllocErr> { + let old_size = layout.size(); debug_assert!( - new_size <= size, - "`new_size` must be smaller than or equal to `memory.size()`" + new_size <= old_size, + "`new_size` must be smaller than or equal to `layout.size()`" ); - if size == new_size { - return Ok(MemoryBlock { ptr, size }); - } - - match placement { - ReallocPlacement::InPlace => Err(AllocErr), - ReallocPlacement::MayMove if new_size == 0 => { - unsafe { - self.dealloc(ptr, layout); - } - Ok(MemoryBlock { ptr: layout.dangling(), size: 0 }) - } - ReallocPlacement::MayMove => { - // `realloc` probably checks for `new_size < size` or something similar. - let ptr = unsafe { - intrinsics::assume(new_size < size); - realloc(ptr.as_ptr(), layout, new_size) - }; - Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }) + let ptr = if new_size == old_size { + ptr + } else if new_size == 0 { + // SAFETY: `layout` is non-zero in size as `old_size` != `new_size` + // Other conditions must be upheld by the caller + unsafe { + self.dealloc(ptr, layout); } - } + layout.dangling() + } else { + // SAFETY: new_size is not zero, + // Other conditions must be upheld by the caller + let raw_ptr = unsafe { + // `realloc` probably checks for `new_size < old_size` or something similar. + intrinsics::assume(new_size < old_size); + realloc(ptr.as_ptr(), layout, new_size) + }; + NonNull::new(raw_ptr).ok_or(AllocErr)? + }; + + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) } } @@ -274,8 +303,8 @@ unsafe fn shrink( #[inline] unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; - match Global.alloc(layout, AllocInit::Uninitialized) { - Ok(memory) => memory.ptr.as_ptr(), + match Global.alloc(layout) { + Ok(ptr) => ptr.as_non_null_ptr().as_ptr(), Err(_) => handle_alloc_error(layout), } } diff --git a/library/alloc/src/alloc/tests.rs b/library/alloc/src/alloc/tests.rs index 1c003983df9..f7463d0daac 100644 --- a/library/alloc/src/alloc/tests.rs +++ b/library/alloc/src/alloc/tests.rs @@ -8,17 +8,16 @@ fn allocate_zeroed() { unsafe { let layout = Layout::from_size_align(1024, 1).unwrap(); - let memory = Global - .alloc(layout.clone(), AllocInit::Zeroed) - .unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = + Global.alloc_zeroed(layout.clone()).unwrap_or_else(|_| handle_alloc_error(layout)); - let mut i = memory.ptr.cast::().as_ptr(); + let mut i = ptr.as_non_null_ptr().as_ptr(); let end = i.add(layout.size()); while i < end { assert_eq!(*i, 0); i = i.offset(1); } - Global.dealloc(memory.ptr, layout); + Global.dealloc(ptr.as_non_null_ptr(), layout); } } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 65e0c984fe8..5e304beff78 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -146,7 +146,7 @@ use core::ptr::{self, Unique}; use core::task::{Context, Poll}; -use crate::alloc::{self, AllocInit, AllocRef, Global}; +use crate::alloc::{self, AllocRef, Global}; use crate::borrow::Cow; use crate::raw_vec::RawVec; use crate::str::from_boxed_utf8_unchecked; @@ -197,11 +197,7 @@ pub fn new(x: T) -> Box { #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_uninit() -> Box> { let layout = alloc::Layout::new::>(); - let ptr = Global - .alloc(layout, AllocInit::Uninitialized) - .unwrap_or_else(|_| alloc::handle_alloc_error(layout)) - .ptr - .cast(); + let ptr = Global.alloc(layout).unwrap_or_else(|_| alloc::handle_alloc_error(layout)).cast(); unsafe { Box::from_raw(ptr.as_ptr()) } } @@ -227,9 +223,8 @@ pub fn new_uninit() -> Box> { pub fn new_zeroed() -> Box> { let layout = alloc::Layout::new::>(); let ptr = Global - .alloc(layout, AllocInit::Zeroed) + .alloc_zeroed(layout) .unwrap_or_else(|_| alloc::handle_alloc_error(layout)) - .ptr .cast(); unsafe { Box::from_raw(ptr.as_ptr()) } } diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 1db629c3bdf..7e27aeb8539 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -1,3 +1,5 @@ +// ignore-tidy-filelength + use core::borrow::Borrow; use core::cmp::Ordering; use core::fmt::Debug; @@ -355,6 +357,30 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { 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 { + inner: IntoIter, +} + +/// 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 { + inner: IntoIter, +} + /// An iterator over a sub-range of entries in a `BTreeMap`. /// /// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its @@ -1291,10 +1317,56 @@ fn dfs<'a, K, V>(node: NodeRef, K, V, marker::LeafOrInternal>) 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 = a.into_keys().collect(); + /// assert_eq!(keys, [1, 2]); + /// ``` + #[inline] + #[unstable(feature = "map_into_keys_values", issue = "75294")] + pub fn into_keys(self) -> IntoKeys { + 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 { + IntoValues { inner: self.into_iter() } + } } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> IntoIterator for &'a BTreeMap { +impl<'a, K, V> IntoIterator for &'a BTreeMap { type Item = (&'a K, &'a V); type IntoIter = Iter<'a, K, V>; @@ -1363,7 +1435,7 @@ fn clone(&self) -> Self { } #[stable(feature = "rust1", since = "1.0.0")] -impl<'a, K: 'a, V: 'a> IntoIterator for &'a mut BTreeMap { +impl<'a, K, V> IntoIterator for &'a mut BTreeMap { type Item = (&'a K, &'a mut V); type IntoIter = IterMut<'a, K, V>; @@ -1697,10 +1769,9 @@ pub(super) fn next(&mut self, pred: &mut F) -> Option<(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()); } @@ -1781,6 +1852,82 @@ unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { } } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl Iterator for IntoKeys { + type Item = K; + + fn next(&mut self) -> Option { + self.inner.next().map(|(k, _)| k) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn last(mut self) -> Option { + self.next_back() + } + + fn min(mut self) -> Option { + self.next() + } + + fn max(mut self) -> Option { + self.next_back() + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl DoubleEndedIterator for IntoKeys { + fn next_back(&mut self) -> Option { + self.inner.next_back().map(|(k, _)| k) + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl ExactSizeIterator for IntoKeys { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl FusedIterator for IntoKeys {} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl Iterator for IntoValues { + type Item = V; + + fn next(&mut self) -> Option { + self.inner.next().map(|(_, v)| v) + } + + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + fn last(mut self) -> Option { + self.next_back() + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl DoubleEndedIterator for IntoValues { + fn next_back(&mut self) -> Option { + self.inner.next_back().map(|(_, v)| v) + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl ExactSizeIterator for IntoValues { + fn len(&self) -> usize { + self.inner.len() + } +} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl FusedIterator for IntoValues {} + #[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)> { @@ -2645,35 +2792,28 @@ pub fn remove(self) -> 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, 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, 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( + self, + handle_emptied_internal_root: F, + ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) + where + F: FnOnce(NodeRef, 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, @@ -2688,17 +2828,16 @@ fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> { 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 { @@ -2719,8 +2858,10 @@ fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> { 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(); @@ -2747,7 +2888,7 @@ fn remove_kv_tracking(self) -> RemoveResult<'a, K, V> { 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) } } diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index 0dcb5930964..33b1ee003ed 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -1,3 +1,5 @@ +use core::intrinsics; +use core::mem; use core::ptr; use super::node::{marker, ForceResult::*, Handle, NodeRef}; @@ -79,16 +81,24 @@ unsafe fn $name ( 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(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { +fn replace(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 } @@ -97,26 +107,22 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Ed /// 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()) + }) } } @@ -127,16 +133,14 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge /// - 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 @@ -145,16 +149,14 @@ pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { /// - 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() } } @@ -172,14 +174,12 @@ impl Handle, marker::Edge> { /// 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 @@ -195,14 +195,12 @@ pub unsafe fn next_unchecked(&mut self) -> (K, V) { /// 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)) + }) } } diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index 6a4c495ea14..4e52c16d20d 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -1083,12 +1083,12 @@ pub fn split(mut self) -> (NodeRef, K, V, marker::Leaf>, K, V, R /// between the now adjacent key/value pairs (if any) to the left and right of this handle. pub fn remove( mut self, - ) -> (Handle, K, V, marker::Leaf>, marker::Edge>, K, V) { + ) -> ((K, V), Handle, 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()) } } } diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 097db30d634..9ac23886d4e 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -104,6 +104,7 @@ #![feature(negative_impls)] #![feature(new_uninit)] #![feature(nll)] +#![feature(nonnull_slice_from_raw_parts)] #![feature(optin_builtin_traits)] #![feature(or_patterns)] #![feature(pattern)] @@ -113,6 +114,8 @@ #![feature(rustc_attrs)] #![feature(receiver_trait)] #![feature(min_specialization)] +#![feature(slice_ptr_get)] +#![feature(slice_ptr_len)] #![feature(staged_api)] #![feature(std_internals)] #![feature(str_internals)] diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index ed81ce71ddf..247b636c808 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -1,25 +1,27 @@ #![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")] #![doc(hidden)] -use core::alloc::{LayoutErr, MemoryBlock}; +use core::alloc::LayoutErr; use core::cmp; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::Drop; use core::ptr::{NonNull, Unique}; use core::slice; -use crate::alloc::{ - handle_alloc_error, - AllocInit::{self, *}, - AllocRef, Global, Layout, - ReallocPlacement::{self, *}, -}; +use crate::alloc::{handle_alloc_error, AllocRef, Global, Layout}; use crate::boxed::Box; use crate::collections::TryReserveError::{self, *}; #[cfg(test)] mod tests; +enum AllocInit { + /// The contents of the new memory are uninitialized. + Uninitialized, + /// The new memory is guaranteed to be zeroed. + Zeroed, +} + /// A low-level utility for more ergonomically allocating, reallocating, and deallocating /// a buffer of memory on the heap without having to worry about all the corner cases /// involved. This type is excellent for building your own data structures like Vec and VecDeque. @@ -156,14 +158,14 @@ pub const fn new_in(alloc: A) -> Self { /// allocator for the returned `RawVec`. #[inline] pub fn with_capacity_in(capacity: usize, alloc: A) -> Self { - Self::allocate_in(capacity, Uninitialized, alloc) + Self::allocate_in(capacity, AllocInit::Uninitialized, alloc) } /// Like `with_capacity_zeroed`, but parameterized over the choice /// of allocator for the returned `RawVec`. #[inline] pub fn with_capacity_zeroed_in(capacity: usize, alloc: A) -> Self { - Self::allocate_in(capacity, Zeroed, alloc) + Self::allocate_in(capacity, AllocInit::Zeroed, alloc) } fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self { @@ -180,14 +182,18 @@ fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self { Ok(_) => {} Err(_) => capacity_overflow(), } - let memory = match alloc.alloc(layout, init) { - Ok(memory) => memory, + let result = match init { + AllocInit::Uninitialized => alloc.alloc(layout), + AllocInit::Zeroed => alloc.alloc_zeroed(layout), + }; + let ptr = match result { + Ok(ptr) => ptr, Err(_) => handle_alloc_error(layout), }; Self { - ptr: unsafe { Unique::new_unchecked(memory.ptr.cast().as_ptr()) }, - cap: Self::capacity_from_bytes(memory.size), + ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }, + cap: Self::capacity_from_bytes(ptr.len()), alloc, } } @@ -197,13 +203,15 @@ fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self { /// /// # 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 @@ -358,7 +366,7 @@ pub fn try_reserve_exact( /// /// Aborts on OOM. pub fn shrink_to_fit(&mut self, amount: usize) { - match self.shrink(amount, MayMove) { + match self.shrink(amount) { Err(CapacityOverflow) => capacity_overflow(), Err(AllocError { layout, .. }) => handle_alloc_error(layout), Ok(()) => { /* yay */ } @@ -378,9 +386,9 @@ fn capacity_from_bytes(excess: usize) -> usize { excess / mem::size_of::() } - fn set_memory(&mut self, memory: MemoryBlock) { - self.ptr = unsafe { Unique::new_unchecked(memory.ptr.cast().as_ptr()) }; - self.cap = Self::capacity_from_bytes(memory.size); + fn set_ptr(&mut self, ptr: NonNull<[u8]>) { + self.ptr = unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) }; + self.cap = Self::capacity_from_bytes(ptr.len()); } // This method is usually instantiated many times. So we want it to be as @@ -426,8 +434,8 @@ fn grow_amortized(&mut self, len: usize, additional: usize) -> Result<(), TryRes let new_layout = Layout::array::(cap); // `finish_grow` is non-generic over `T`. - let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; - self.set_memory(memory); + let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; + self.set_ptr(ptr); Ok(()) } @@ -445,30 +453,24 @@ fn grow_exact(&mut self, len: usize, additional: usize) -> Result<(), TryReserve let new_layout = Layout::array::(cap); // `finish_grow` is non-generic over `T`. - let memory = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; - self.set_memory(memory); + let ptr = finish_grow(new_layout, self.current_memory(), &mut self.alloc)?; + self.set_ptr(ptr); Ok(()) } - fn shrink( - &mut self, - amount: usize, - placement: ReallocPlacement, - ) -> Result<(), TryReserveError> { + fn shrink(&mut self, amount: usize) -> Result<(), TryReserveError> { assert!(amount <= self.capacity(), "Tried to shrink to a larger capacity"); let (ptr, layout) = if let Some(mem) = self.current_memory() { mem } else { return Ok(()) }; let new_size = amount * mem::size_of::(); - let memory = unsafe { - self.alloc.shrink(ptr, layout, new_size, placement).map_err(|_| { - TryReserveError::AllocError { - layout: Layout::from_size_align_unchecked(new_size, layout.align()), - non_exhaustive: (), - } + let ptr = unsafe { + self.alloc.shrink(ptr, layout, new_size).map_err(|_| TryReserveError::AllocError { + layout: Layout::from_size_align_unchecked(new_size, layout.align()), + non_exhaustive: (), })? }; - self.set_memory(memory); + self.set_ptr(ptr); Ok(()) } } @@ -481,7 +483,7 @@ fn finish_grow( new_layout: Result, current_memory: Option<(NonNull, Layout)>, alloc: &mut A, -) -> Result +) -> Result, TryReserveError> where A: AllocRef, { @@ -492,9 +494,9 @@ fn finish_grow( let memory = if let Some((ptr, old_layout)) = current_memory { debug_assert_eq!(old_layout.align(), new_layout.align()); - unsafe { alloc.grow(ptr, old_layout, new_layout.size(), MayMove, Uninitialized) } + unsafe { alloc.grow(ptr, old_layout, new_layout.size()) } } else { - alloc.alloc(new_layout, Uninitialized) + alloc.alloc(new_layout) } .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?; diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index 5408faa079c..cadd913aa6b 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -20,12 +20,12 @@ struct BoundedAlloc { fuel: usize, } unsafe impl AllocRef for BoundedAlloc { - fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result { + fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { let size = layout.size(); if size > self.fuel { return Err(AllocErr); } - match Global.alloc(layout, init) { + match Global.alloc(layout) { ok @ Ok(_) => { self.fuel -= size; ok diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 1c61050147d..d0a47ccea0a 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -250,7 +250,7 @@ use core::ptr::{self, NonNull}; use core::slice::from_raw_parts_mut; -use crate::alloc::{box_free, handle_alloc_error, AllocInit, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::string::String; use crate::vec::Vec; @@ -928,12 +928,10 @@ unsafe fn allocate_for_layout( let layout = Layout::new::>().extend(value_layout).unwrap().0.pad_to_align(); // Allocate for the layout. - let mem = Global - .alloc(layout, AllocInit::Uninitialized) - .unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the RcBox - let inner = mem_to_rcbox(mem.ptr.as_ptr()); + let inner = mem_to_rcbox(ptr.as_non_null_ptr().as_ptr()); unsafe { debug_assert_eq!(Layout::for_value(&*inner), layout); diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 343a17b002f..b3763303137 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -23,7 +23,7 @@ use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use crate::alloc::{box_free, handle_alloc_error, AllocInit, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -883,12 +883,10 @@ unsafe fn allocate_for_layout( // reference (see #54908). let layout = Layout::new::>().extend(value_layout).unwrap().0.pad_to_align(); - let mem = Global - .alloc(layout, AllocInit::Uninitialized) - .unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); // Initialize the ArcInner - let inner = mem_to_arcinner(mem.ptr.as_ptr()); + let inner = mem_to_arcinner(ptr.as_non_null_ptr().as_ptr()); debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout); unsafe { @@ -988,7 +986,7 @@ fn drop(&mut self) { let slice = from_raw_parts_mut(self.elems, self.n_elems); ptr::drop_in_place(slice); - Global.dealloc(self.mem.cast(), self.layout); + Global.dealloc(self.mem, self.layout); } } } diff --git a/library/alloc/tests/btree/map.rs b/library/alloc/tests/btree/map.rs index f9f81716e35..5777bd60907 100644 --- a/library/alloc/tests/btree/map.rs +++ b/library/alloc/tests/btree/map.rs @@ -1461,3 +1461,27 @@ fn drop(&mut self) { 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')); +} diff --git a/library/alloc/tests/heap.rs b/library/alloc/tests/heap.rs index 62f062b83d7..cbde2a7e28e 100644 --- a/library/alloc/tests/heap.rs +++ b/library/alloc/tests/heap.rs @@ -1,4 +1,4 @@ -use std::alloc::{AllocInit, AllocRef, Global, Layout, System}; +use std::alloc::{AllocRef, Global, Layout, System}; /// Issue #45955 and #62251. #[test] @@ -20,18 +20,12 @@ fn check_overalign_requests(mut allocator: T) { unsafe { let pointers: Vec<_> = (0..iterations) .map(|_| { - allocator - .alloc( - Layout::from_size_align(size, align).unwrap(), - AllocInit::Uninitialized, - ) - .unwrap() - .ptr + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() }) .collect(); for &ptr in &pointers { assert_eq!( - (ptr.as_ptr() as usize) % align, + (ptr.as_non_null_ptr().as_ptr() as usize) % align, 0, "Got a pointer less aligned than requested" ) @@ -39,7 +33,10 @@ fn check_overalign_requests(mut allocator: T) { // Clean up for &ptr in &pointers { - allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + allocator.dealloc( + ptr.as_non_null_ptr(), + Layout::from_size_align(size, align).unwrap(), + ) } } } diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index fa20a466715..3aacd4a687e 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -4,6 +4,7 @@ #![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)] @@ -13,6 +14,7 @@ #![feature(associated_type_bounds)] #![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_drain_sorted)] +#![feature(slice_ptr_get)] #![feature(split_inclusive)] #![feature(binary_heap_retain)] diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index be4e051b1ca..2833768f213 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -29,92 +29,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } -/// A desired initial state for allocated memory. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[unstable(feature = "allocator_api", issue = "32838")] -pub enum AllocInit { - /// The contents of the new memory are uninitialized. - Uninitialized, - /// The new memory is guaranteed to be zeroed. - Zeroed, -} - -impl AllocInit { - /// Initialize the specified memory block. - /// - /// This behaves like calling [`AllocInit::init_offset(memory, 0)`][off]. - /// - /// [off]: AllocInit::init_offset - /// - /// # Safety - /// - /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes. - /// - /// [valid]: ../../core/ptr/index.html#safety - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn init(self, memory: MemoryBlock) { - // SAFETY: the safety contract for `init_offset` must be - // upheld by the caller. - unsafe { self.init_offset(memory, 0) } - } - - /// Initialize the memory block like specified by `init` at the specified `offset`. - /// - /// This is a no-op for [`AllocInit::Uninitialized`][] and writes zeroes for - /// [`AllocInit::Zeroed`][] at `ptr + offset` until `ptr + layout.size()`. - /// - /// # Safety - /// - /// * `memory.ptr` must be [valid] for writes of `memory.size` bytes. - /// * `offset` must be smaller than or equal to `memory.size` - /// - /// [valid]: ../../core/ptr/index.html#safety - #[inline] - #[unstable(feature = "allocator_api", issue = "32838")] - pub unsafe fn init_offset(self, memory: MemoryBlock, offset: usize) { - debug_assert!( - offset <= memory.size, - "`offset` must be smaller than or equal to `memory.size`" - ); - match self { - AllocInit::Uninitialized => (), - AllocInit::Zeroed => { - // SAFETY: the caller must guarantee that `offset` is smaller than or equal to `memory.size`, - // so the memory from `memory.ptr + offset` of length `memory.size - offset` - // is guaranteed to be contaned in `memory` and thus valid for writes. - unsafe { memory.ptr.as_ptr().add(offset).write_bytes(0, memory.size - offset) } - } - } - } -} - -/// Represents a block of allocated memory returned by an allocator. -#[derive(Debug, Copy, Clone)] -#[unstable(feature = "allocator_api", issue = "32838")] -pub struct MemoryBlock { - pub ptr: NonNull, - pub size: usize, -} - -/// A placement constraint when growing or shrinking an existing allocation. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -#[unstable(feature = "allocator_api", issue = "32838")] -pub enum ReallocPlacement { - /// The allocator is allowed to move the allocation to a different memory address. - // FIXME(wg-allocators#46): Add a section to the module documentation "What is a legal - // allocator" and link it at "valid location". - /// - /// If the allocation _does_ move, it's the responsibility of the allocator - /// to also move the data from the previous location to the new location. - MayMove, - /// The address of the new memory must not change. - /// - /// If the allocation would have to be moved to a new location to fit, the - /// reallocation request will fail. - InPlace, -} - /// An implementation of `AllocRef` can allocate, grow, shrink, and deallocate arbitrary blocks of /// data described via [`Layout`][]. /// @@ -175,12 +89,12 @@ pub enum ReallocPlacement { pub unsafe trait AllocRef { /// Attempts to allocate a block of memory. /// - /// On success, returns a [`MemoryBlock`][] meeting the size and alignment guarantees of `layout`. + /// On success, returns a [`NonNull<[u8]>`] meeting the size and alignment guarantees of `layout`. /// - /// The returned block may have a larger size than specified by `layout.size()` and is - /// initialized as specified by [`init`], all the way up to the returned size of the block. + /// The returned block may have a larger size than specified by `layout.size()`, and may or may + /// not have its contents initialized. /// - /// [`init`]: AllocInit + /// [`NonNull<[u8]>`]: NonNull /// /// # Errors /// @@ -195,7 +109,29 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result; + fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + + /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized. + /// + /// # Errors + /// + /// Returning `Err` indicates that either memory is exhausted or `layout` does not meet + /// allocator's size or alignment constraints. + /// + /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement + /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an allocation error are encouraged to + /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + let ptr = self.alloc(layout)?; + // SAFETY: `alloc` returns a valid memory block + unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) } + Ok(ptr) + } /// Deallocates the memory referenced by `ptr`. /// @@ -210,44 +146,100 @@ pub unsafe trait AllocRef { /// Attempts to extend the memory block. /// - /// Returns a new [`MemoryBlock`][] containing a pointer and the actual size of the allocated + /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the - /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is - /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`. - /// - /// If [`MayMove`] is used then ownership of the memory block referenced by `ptr` - /// is transferred to this allocator. The memory may or may not be freed, and should be - /// considered unusable (unless of course it is transferred back to the caller again via the - /// return value of this method). + /// allocation referenced by `ptr` to fit the new layout. /// /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. /// - /// The memory block will contain the following contents after a successful call to `grow`: + /// [`NonNull<[u8]>`]: NonNull + /// + /// # Safety + /// + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, + /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), + /// * `new_size` must be greater than or equal to `layout.size()`, and + /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow + /// (i.e., the rounded value must be less than or equal to `usize::MAX`). + // Note: We can't require that `new_size` is strictly greater than `layout.size()` because of ZSTs. + // alternative: `new_size` must be strictly greater than `layout.size()` or both are zero + /// + /// [*currently allocated*]: #currently-allocated-memory + /// [*fit*]: #memory-fitting + /// + /// # Errors + /// + /// Returns `Err` if the new layout does not meet the allocator's size and alignment + /// constraints of the allocator, or if growing otherwise fails. + /// + /// Implementations are encouraged to return `Err` on memory exhaustion rather than panicking or + /// aborting, but this is not a strict requirement. (Specifically: it is *legal* to implement + /// this trait atop an underlying native allocation library that aborts on memory exhaustion.) + /// + /// Clients wishing to abort computation in response to an allocation error are encouraged to + /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. + /// + /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html + unsafe fn grow( + &mut self, + ptr: NonNull, + layout: Layout, + new_size: usize, + ) -> Result, AllocErr> { + let size = layout.size(); + debug_assert!( + new_size >= size, + "`new_size` must be greater than or equal to `layout.size()`" + ); + + if size == new_size { + return Ok(NonNull::slice_from_raw_parts(ptr, size)); + } + + let new_layout = + // SAFETY: the caller must ensure that the `new_size` does not overflow. + // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. + // The caller must ensure that `new_size` is greater than or equal to zero. If it's equal + // to zero, it's catched beforehand. + unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; + let new_ptr = self.alloc(new_layout)?; + + // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new + // memory allocation are valid for reads and writes for `size` bytes. Also, because the old + // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to + // `copy_nonoverlapping` is safe. + // The safety contract for `dealloc` must be upheld by the caller. + unsafe { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_non_null_ptr().as_ptr(), size); + self.dealloc(ptr, layout); + Ok(new_ptr) + } + } + + /// Behaves like `grow`, but also ensures that the new contents are set to zero before being + /// returned. + /// + /// The memory block will contain the following contents after a successful call to + /// `grow_zeroed`: /// * Bytes `0..layout.size()` are preserved from the original allocation. - /// * Bytes `layout.size()..old_size` will either be preserved or initialized according to - /// [`init`], depending on the allocator implementation. `old_size` refers to the size of - /// the `MemoryBlock` prior to the `grow` call, which may be larger than the size + /// * Bytes `layout.size()..old_size` will either be preserved or zeroed, + /// depending on the allocator implementation. `old_size` refers to the size of + /// the `MemoryBlock` prior to the `grow_zeroed` call, which may be larger than the size /// that was originally requested when it was allocated. - /// * Bytes `old_size..new_size` are initialized according to [`init`]. `new_size` refers to + /// * Bytes `old_size..new_size` are zeroed. `new_size` refers to /// the size of the `MemoryBlock` returned by the `grow` call. /// - /// [`InPlace`]: ReallocPlacement::InPlace - /// [`MayMove`]: ReallocPlacement::MayMove - /// [`placement`]: ReallocPlacement - /// [`init`]: AllocInit - /// /// # Safety /// /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), - // We can't require that `new_size` is strictly greater than `memory.size` because of ZSTs. - // An alternative would be - // * `new_size must be strictly greater than `memory.size` or both are zero /// * `new_size` must be greater than or equal to `layout.size()`, and /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow /// (i.e., the rounded value must be less than or equal to `usize::MAX`). + // Note: We can't require that `new_size` is strictly greater than `layout.size()` because of ZSTs. + // alternative: `new_size` must be strictly greater than `layout.size()` or both are zero /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -265,55 +257,48 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - unsafe fn grow( + unsafe fn grow_zeroed( &mut self, ptr: NonNull, layout: Layout, new_size: usize, - placement: ReallocPlacement, - init: AllocInit, - ) -> Result { - match placement { - ReallocPlacement::InPlace => Err(AllocErr), - ReallocPlacement::MayMove => { - let size = layout.size(); - debug_assert!( - new_size >= size, - "`new_size` must be greater than or equal to `layout.size()`" - ); + ) -> Result, AllocErr> { + let size = layout.size(); + debug_assert!( + new_size >= size, + "`new_size` must be greater than or equal to `layout.size()`" + ); - if new_size == size { - return Ok(MemoryBlock { ptr, size }); - } + if size == new_size { + return Ok(NonNull::slice_from_raw_parts(ptr, size)); + } - let new_layout = - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - // The caller must ensure that `new_size` is greater than zero. - unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; - let new_memory = self.alloc(new_layout, init)?; + let new_layout = + // SAFETY: the caller must ensure that the `new_size` does not overflow. + // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. + // The caller must ensure that `new_size` is greater than or equal to zero. If it's equal + // to zero, it's caught beforehand. + unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; + let new_ptr = self.alloc_zeroed(new_layout)?; - // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `size` bytes. Also, because the old - // allocation wasn't yet deallocated, it cannot overlap `new_memory`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. - unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), size); - self.dealloc(ptr, layout); - Ok(new_memory) - } - } + // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new + // memory allocation are valid for reads and writes for `size` bytes. Also, because the old + // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to + // `copy_nonoverlapping` is safe. + // The safety contract for `dealloc` must be upheld by the caller. + unsafe { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_non_null_ptr().as_ptr(), size); + self.dealloc(ptr, layout); + Ok(new_ptr) } } /// Attempts to shrink the memory block. /// - /// Returns a new [`MemoryBlock`][] containing a pointer and the actual size of the allocated + /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the - /// allocation referenced by `ptr` to fit the new layout. If the [`placement`] is - /// [`InPlace`], the returned pointer is guaranteed to be the same as the passed `ptr`. + /// allocation referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// transferred to this allocator. The memory may or may not have been freed, and should be @@ -323,19 +308,15 @@ unsafe fn grow( /// If this method returns `Err`, then ownership of the memory block has not been transferred to /// this allocator, and the contents of the memory block are unaltered. /// - /// The behavior of how the allocator tries to shrink the memory is specified by [`placement`]. - /// - /// [`InPlace`]: ReallocPlacement::InPlace - /// [`placement`]: ReallocPlacement + /// [`NonNull<[u8]>`]: NonNull /// /// # Safety /// /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), and - // We can't require that `new_size` is strictly smaller than `memory.size` because of ZSTs. - // An alternative would be - // * `new_size must be strictly smaller than `memory.size` or both are zero /// * `new_size` must be smaller than or equal to `layout.size()`. + // Note: We can't require that `new_size` is strictly smaller than `layout.size()` because of ZSTs. + // alternative: `new_size` must be smaller than `layout.size()` or both are zero /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -358,39 +339,33 @@ unsafe fn shrink( ptr: NonNull, layout: Layout, new_size: usize, - placement: ReallocPlacement, - ) -> Result { - match placement { - ReallocPlacement::InPlace => Err(AllocErr), - ReallocPlacement::MayMove => { - let size = layout.size(); - debug_assert!( - new_size <= size, - "`new_size` must be smaller than or equal to `layout.size()`" - ); + ) -> Result, AllocErr> { + let size = layout.size(); + debug_assert!( + new_size <= size, + "`new_size` must be smaller than or equal to `layout.size()`" + ); - if new_size == size { - return Ok(MemoryBlock { ptr, size }); - } + if size == new_size { + return Ok(NonNull::slice_from_raw_parts(ptr, size)); + } - let new_layout = - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - // The caller must ensure that `new_size` is greater than zero. - unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; - let new_memory = self.alloc(new_layout, AllocInit::Uninitialized)?; + let new_layout = + // SAFETY: the caller must ensure that the `new_size` does not overflow. + // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. + // The caller must ensure that `new_size` is greater than zero. + unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; + let new_ptr = self.alloc(new_layout)?; - // SAFETY: because `new_size` must be lower than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `new_size` bytes. Also, because the - // old allocation wasn't yet deallocated, it cannot overlap `new_memory`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. - unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_memory.ptr.as_ptr(), new_size); - self.dealloc(ptr, layout); - Ok(new_memory) - } - } + // SAFETY: because `new_size` must be lower than or equal to `size`, both the old and new + // memory allocation are valid for reads and writes for `new_size` bytes. Also, because the + // old allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to + // `copy_nonoverlapping` is safe. + // The safety contract for `dealloc` must be upheld by the caller. + unsafe { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_non_null_ptr().as_ptr(), size); + self.dealloc(ptr, layout); + Ok(new_ptr) } } @@ -409,8 +384,13 @@ unsafe impl AllocRef for &mut A A: AllocRef + ?Sized, { #[inline] - fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result { - (**self).alloc(layout, init) + fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + (**self).alloc(layout) + } + + #[inline] + fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + (**self).alloc_zeroed(layout) } #[inline] @@ -425,11 +405,20 @@ unsafe fn grow( ptr: NonNull, layout: Layout, new_size: usize, - placement: ReallocPlacement, - init: AllocInit, - ) -> Result { + ) -> Result, AllocErr> { + // SAFETY: the safety contract must be upheld by the caller + unsafe { (**self).grow(ptr, layout, new_size) } + } + + #[inline] + unsafe fn grow_zeroed( + &mut self, + ptr: NonNull, + layout: Layout, + new_size: usize, + ) -> Result, AllocErr> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).grow(ptr, layout, new_size, placement, init) } + unsafe { (**self).grow_zeroed(ptr, layout, new_size) } } #[inline] @@ -438,9 +427,8 @@ unsafe fn shrink( ptr: NonNull, layout: Layout, new_size: usize, - placement: ReallocPlacement, - ) -> Result { + ) -> Result, AllocErr> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).shrink(ptr, layout, new_size, placement) } + unsafe { (**self).shrink(ptr, layout, new_size) } } } diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 174f7e26efb..919070aadf9 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -56,38 +56,34 @@ impl IntoIter { // FIXME(LukasKalbertodt): actually use `mem::transmute` here, once it // works with const generics: - // `mem::transmute::<[T; {N}], [MaybeUninit; {N}]>(array)` + // `mem::transmute::<[T; N], [MaybeUninit; 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; 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]>(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], &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) + } } } @@ -95,30 +91,20 @@ fn as_mut_slice(&mut self) -> &mut [T] { impl Iterator for IntoIter { type Item = T; fn next(&mut self) -> Option { - 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) { @@ -138,33 +124,20 @@ fn last(mut self) -> Option { #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { - 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() } + }) } } @@ -203,26 +176,19 @@ unsafe impl TrustedLen for IntoIter {} #[stable(feature = "array_value_iter_impls", since = "1.40.0")] impl Clone for IntoIter { 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; 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 } } diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 3116815f5d6..3dc0ee2b555 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -119,9 +119,11 @@ pub fn black_box(dummy: T) -> T { // 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 } diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 44b86438f2a..3a28bc79eff 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1950,15 +1950,20 @@ pub fn ptr_offset_from(ptr: *const T, base: *const T) -> isize; /// Internal placeholder for injecting code coverage counters when the "instrument-coverage" - /// option is enabled. The placeholder is replaced with `llvm.instrprof.increment` during code - /// generation. + /// option is enabled. The source code region information is extracted prior to code generation, + /// and added to the "coverage map", which is injected into the generated code as additional + /// data. This intrinsic then triggers the generation of LLVM intrinsic call + /// `instrprof.increment`, using the remaining args (`function_source_hash` and `index`). #[cfg(not(bootstrap))] #[lang = "count_code_region"] pub fn count_code_region( function_source_hash: u64, index: u32, - start_byte_pos: u32, - end_byte_pos: u32, + file_name: &'static str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, ); /// Internal marker for code coverage expressions, injected into the MIR when the @@ -1973,8 +1978,11 @@ pub fn coverage_counter_add( index: u32, left_index: u32, right_index: u32, - start_byte_pos: u32, - end_byte_pos: u32, + file_name: &'static str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, ); /// This marker identifies a code region and two other counters or counter expressions @@ -1986,14 +1994,24 @@ pub fn coverage_counter_subtract( index: u32, left_index: u32, right_index: u32, - start_byte_pos: u32, - end_byte_pos: u32, + file_name: &'static str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, ); /// This marker identifies a code region to be added to the "coverage map" to indicate source /// code that can never be reached. /// (See `coverage_counter_add` for more information.) - pub fn coverage_unreachable(start_byte_pos: u32, end_byte_pos: u32); + #[cfg(not(bootstrap))] + pub fn coverage_unreachable( + file_name: &'static str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, + ); /// See documentation of `<*const T>::guaranteed_eq` for details. #[rustc_const_unstable(feature = "const_raw_ptr_comparison", issue = "53020")] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index cf721b01ce3..027498d3911 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -405,9 +405,11 @@ pub fn write(&mut self, val: T) -> &mut T { /// (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 @@ -442,9 +444,11 @@ pub fn as_ptr(&self) -> *const T { /// (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` container. This is a great way diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index eb50dc28b9f..68937176270 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -2346,17 +2346,12 @@ pub const fn is_negative(self) -> bool { self < 0 } #[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::()] { - #[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) } } } @@ -2464,16 +2459,11 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[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 { - #[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) } } } @@ -4368,23 +4358,18 @@ pub const fn wrapping_next_power_of_two(self) -> 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 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::()] { - #[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, " @@ -4416,8 +4401,8 @@ fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), 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, " @@ -4448,8 +4433,8 @@ fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), } 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 @@ -4486,16 +4471,11 @@ fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), #[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 { - #[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) } } } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index a2acc239bd3..a16970e9fd1 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -656,6 +656,38 @@ pub const fn wrapping_sub(self, count: usize) -> Self 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. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 17fa90ecc08..b47f90c5996 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -712,6 +712,38 @@ pub const fn wrapping_sub(self, count: usize) -> Self 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. /// diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 9f843a57099..d876ab23653 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -117,6 +117,24 @@ pub const fn as_ptr(self) -> *mut 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 `&*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 { @@ -130,6 +148,24 @@ 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 { @@ -224,6 +260,24 @@ pub const fn as_non_null_ptr(self) -> NonNull { 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. /// diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index 9d7e38d0e18..eac4741cd26 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1923,7 +1923,10 @@ unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { #[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 { @@ -1995,7 +1998,10 @@ unsafe fn get_unchecked_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 { @@ -2068,7 +2074,10 @@ unsafe fn get_unchecked_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 { diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 72eab0763d8..7d14893c4cc 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -50,6 +50,7 @@ } 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"), ))] { @@ -65,7 +66,6 @@ // - os=uefi // - nvptx64-nvidia-cuda // - avr-unknown-unknown - // - mipsel-sony-psp #[path = "dummy.rs"] mod real_imp; } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 474765d8638..fc07fa77b85 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -20,7 +20,7 @@ libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of 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 } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index c44ce9873d5..4712cc95b4a 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -140,28 +140,35 @@ #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl AllocRef for System { #[inline] - fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result { - unsafe { - let size = layout.size(); - if size == 0 { - Ok(MemoryBlock { ptr: layout.dangling(), size: 0 }) - } else { - let raw_ptr = match init { - AllocInit::Uninitialized => GlobalAlloc::alloc(self, layout), - AllocInit::Zeroed => GlobalAlloc::alloc_zeroed(self, layout), - }; - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; - Ok(MemoryBlock { ptr, size }) - } - } + fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + let size = layout.size(); + let ptr = if size == 0 { + layout.dangling() + } else { + // SAFETY: `layout` is non-zero in size, + unsafe { NonNull::new(GlobalAlloc::alloc(&System, layout)).ok_or(AllocErr)? } + }; + Ok(NonNull::slice_from_raw_parts(ptr, size)) + } + + #[inline] + fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + let size = layout.size(); + let ptr = if size == 0 { + layout.dangling() + } else { + // SAFETY: `layout` is non-zero in size, + unsafe { NonNull::new(GlobalAlloc::alloc_zeroed(&System, layout)).ok_or(AllocErr)? } + }; + Ok(NonNull::slice_from_raw_parts(ptr, size)) } #[inline] unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { - // SAFETY: The safety guarantees are explained in the documentation - // for the `GlobalAlloc` trait and its `dealloc` method. - unsafe { GlobalAlloc::dealloc(self, ptr.as_ptr(), layout) } + // SAFETY: `layout` is non-zero in size, + // other conditions must be upheld by the caller + unsafe { GlobalAlloc::dealloc(&System, ptr.as_ptr(), layout) } } } @@ -171,53 +178,59 @@ unsafe fn grow( ptr: NonNull, layout: Layout, new_size: usize, - placement: ReallocPlacement, - init: AllocInit, - ) -> Result { - let size = layout.size(); + ) -> Result, AllocErr> { debug_assert!( - new_size >= size, - "`new_size` must be greater than or equal to `memory.size()`" + new_size >= layout.size(), + "`new_size` must be greater than or equal to `layout.size()`" ); - if size == new_size { - return Ok(MemoryBlock { ptr, size }); + // SAFETY: `new_size` must be non-zero, which is checked in the match expression. + // Other conditions must be upheld by the caller + unsafe { + match layout.size() { + old_size if old_size == new_size => { + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + } + 0 => self.alloc(Layout::from_size_align_unchecked(new_size, layout.align())), + old_size => { + // `realloc` probably checks for `new_size > size` or something similar. + intrinsics::assume(new_size > old_size); + let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + } + } } + } - match placement { - ReallocPlacement::InPlace => Err(AllocErr), - ReallocPlacement::MayMove if layout.size() == 0 => { - let new_layout = - // SAFETY: The new size and layout alignement guarantees - // are transferred to the caller (they come from parameters). - // - // See the preconditions for `Layout::from_size_align` to - // see what must be checked. - unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; - self.alloc(new_layout, init) - } - ReallocPlacement::MayMove => { - // SAFETY: - // - // The safety guarantees are explained in the documentation - // for the `GlobalAlloc` trait and its `dealloc` method. - // - // `realloc` probably checks for `new_size > size` or something - // similar. - // - // For the guarantees about `init_offset`, see its documentation: - // `ptr` is assumed valid (and checked for non-NUL) and - // `memory.size` is set to `new_size` so the offset being `size` - // is valid. - let memory = unsafe { - intrinsics::assume(new_size > size); - let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size); - let memory = - MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size }; - init.init_offset(memory, size); - memory - }; - Ok(memory) + #[inline] + unsafe fn grow_zeroed( + &mut self, + ptr: NonNull, + layout: Layout, + new_size: usize, + ) -> Result, AllocErr> { + debug_assert!( + new_size >= layout.size(), + "`new_size` must be greater than or equal to `layout.size()`" + ); + + // SAFETY: `new_size` must be non-zero, which is checked in the match expression. + // Other conditions must be upheld by the caller + unsafe { + match layout.size() { + old_size if old_size == new_size => { + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + } + 0 => self.alloc_zeroed(Layout::from_size_align_unchecked(new_size, layout.align())), + old_size => { + // `realloc` probably checks for `new_size > size` or something similar. + intrinsics::assume(new_size > old_size); + let raw_ptr = GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size); + raw_ptr.add(old_size).write_bytes(0, new_size - old_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) + } } } } @@ -228,45 +241,34 @@ unsafe fn shrink( ptr: NonNull, layout: Layout, new_size: usize, - placement: ReallocPlacement, - ) -> Result { - let size = layout.size(); + ) -> Result, AllocErr> { + let old_size = layout.size(); debug_assert!( - new_size <= size, - "`new_size` must be smaller than or equal to `memory.size()`" + new_size <= old_size, + "`new_size` must be smaller than or equal to `layout.size()`" ); - if size == new_size { - return Ok(MemoryBlock { ptr, size }); - } - - match placement { - ReallocPlacement::InPlace => Err(AllocErr), - ReallocPlacement::MayMove if new_size == 0 => { - // SAFETY: see `GlobalAlloc::dealloc` for the guarantees that - // must be respected. `ptr` and `layout` are parameters and so - // those guarantees must be checked by the caller. - unsafe { self.dealloc(ptr, layout) }; - Ok(MemoryBlock { ptr: layout.dangling(), size: 0 }) + let ptr = if new_size == old_size { + ptr + } else if new_size == 0 { + // SAFETY: `layout` is non-zero in size as `old_size` != `new_size` + // Other conditions must be upheld by the caller + unsafe { + self.dealloc(ptr, layout); } - ReallocPlacement::MayMove => { - // SAFETY: - // - // See `GlobalAlloc::realloc` for more informations about the - // guarantees expected by this method. `ptr`, `layout` and - // `new_size` are parameters and the responsibility for their - // correctness is left to the caller. - // - // `realloc` probably checks for `new_size < size` or something - // similar. - let memory = unsafe { - intrinsics::assume(new_size < size); - let ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size); - MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size } - }; - Ok(memory) - } - } + layout.dangling() + } else { + // SAFETY: new_size is not zero, + // Other conditions must be upheld by the caller + let raw_ptr = unsafe { + // `realloc` probably checks for `new_size < old_size` or something similar. + intrinsics::assume(new_size < old_size); + GlobalAlloc::realloc(&System, ptr.as_ptr(), layout, new_size) + }; + NonNull::new(raw_ptr).ok_or(AllocErr)? + }; + + Ok(NonNull::slice_from_raw_parts(ptr, new_size)) } } static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut()); diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 7b48deee1ab..70f7214e2f1 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -580,7 +580,7 @@ pub fn reserve(&mut self, additional: usize) { #[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 @@ -872,6 +872,52 @@ pub fn retain(&mut self, f: F) { 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 { + 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 = map.into_values().collect(); + /// ``` + #[inline] + #[unstable(feature = "map_into_keys_values", issue = "75294")] + pub fn into_values(self) -> IntoValues { + IntoValues { inner: self.into_iter() } + } } impl HashMap @@ -1154,6 +1200,28 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { 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 { + inner: IntoIter, +} + +/// 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 { + inner: IntoIter, +} + /// 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. @@ -1827,6 +1895,66 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl Iterator for IntoKeys { + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(k, _)| k) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl ExactSizeIterator for IntoKeys { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl FusedIterator for IntoKeys {} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoKeys { + 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 Iterator for IntoValues { + type Item = V; + + #[inline] + fn next(&mut self) -> Option { + self.inner.next().map(|(_, v)| v) + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl ExactSizeIterator for IntoValues { + #[inline] + fn len(&self) -> usize { + self.inner.len() + } +} +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl FusedIterator for IntoValues {} + +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoValues { + 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); @@ -2569,10 +2697,10 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, } #[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: () } } } @@ -3084,6 +3212,30 @@ fn test_values_mut() { 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(); diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index c98008688ab..ff343625a19 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -943,8 +943,7 @@ mod mod_keyword {} /// 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"; @@ -953,6 +952,23 @@ mod mod_keyword {} /// }; /// ``` /// +/// 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 diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index c81b949af65..0569e46241a 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -291,6 +291,7 @@ #![feature(negative_impls)] #![feature(never_type)] #![feature(nll)] +#![feature(nonnull_slice_from_raw_parts)] #![feature(once_cell)] #![feature(optin_builtin_traits)] #![feature(or_patterns)] @@ -308,6 +309,8 @@ #![feature(shrink_to)] #![feature(slice_concat_ext)] #![feature(slice_internals)] +#![feature(slice_ptr_get)] +#![feature(slice_ptr_len)] #![feature(slice_strip)] #![feature(staged_api)] #![feature(std_internals)] diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index a64b43ca3ad..159ab981b23 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -319,15 +319,9 @@ impl Ipv4Addr { #[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. @@ -967,11 +961,6 @@ fn as_inner(&self) -> &c::in_addr { &self.inner } } -impl FromInner for Ipv4Addr { - fn from_inner(addr: c::in_addr) -> Ipv4Addr { - Ipv4Addr { inner: addr } - } -} #[stable(feature = "ip_u32", since = "1.1.0")] impl From for u32 { @@ -982,8 +971,8 @@ impl From 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(); @@ -1000,8 +989,8 @@ impl From for Ipv4Addr { /// ``` /// 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()) diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index ab2a6010306..21ab0faed3e 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -434,7 +434,9 @@ fn get(&mut self) -> &(dyn Any + Send) { 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 @@ -453,7 +455,10 @@ pub fn begin_panic(msg: M) -> ! { 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 { inner: Option, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 392c815ef28..a468f6b4b8d 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -56,16 +56,8 @@ //! 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")] @@ -390,12 +382,9 @@ enum State { /// # } /// ``` /// -/// [`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> { @@ -411,16 +400,12 @@ impl<'a> 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 @@ -477,10 +462,6 @@ fn hash(&self, h: &mut H) { /// 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> { @@ -490,8 +471,6 @@ 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>), @@ -529,8 +508,6 @@ impl<'a> Component<'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 { @@ -574,9 +551,7 @@ fn as_ref(&self) -> &Path { /// } /// ``` /// -/// [`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> { @@ -602,10 +577,7 @@ 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> { @@ -1002,8 +974,7 @@ fn cmp(&self, other: &Self) -> cmp::Ordering { /// } /// ``` /// -/// [`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> { @@ -1034,11 +1005,8 @@ impl FusedIterator for Ancestors<'_> {} /// 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). @@ -1127,8 +1095,7 @@ pub fn new() -> PathBuf { /// 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) } @@ -1136,8 +1103,6 @@ pub fn with_capacity(capacity: usize) -> PathBuf { /// Coerces to a [`Path`] slice. /// - /// [`Path`]: struct.Path.html - /// /// # Examples /// /// ``` @@ -1224,18 +1189,17 @@ fn _push(&mut self, path: &Path) { /// 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); /// ``` @@ -1259,9 +1223,8 @@ pub fn pop(&mut self) -> bool { /// `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 /// @@ -1297,9 +1260,8 @@ fn _set_file_name(&mut self, file_name: &OsStr) { /// 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 /// @@ -1344,8 +1306,6 @@ fn _set_extension(&mut self, extension: &OsStr) -> bool { /// Consumes the `PathBuf`, yielding its internal [`OsString`] storage. /// - /// [`OsString`]: ../ffi/struct.OsString.html - /// /// # Examples /// /// ``` @@ -1360,9 +1320,6 @@ pub fn into_os_string(self) -> OsString { } /// 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 { let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path; @@ -1371,8 +1328,7 @@ pub fn into_boxed_path(self) -> Box { /// 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() @@ -1380,8 +1336,7 @@ pub fn capacity(&self) -> usize { /// 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() @@ -1389,8 +1344,7 @@ pub fn clear(&mut self) { /// 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) @@ -1398,8 +1352,7 @@ pub fn reserve(&mut self, additional: usize) { /// 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) @@ -1407,8 +1360,7 @@ pub fn reserve_exact(&mut self, additional: usize) { /// 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() @@ -1416,8 +1368,7 @@ pub fn shrink_to_fit(&mut self) { /// 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) @@ -1703,10 +1654,6 @@ fn as_ref(&self) -> &OsStr { /// 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). /// @@ -1745,8 +1692,7 @@ pub struct Path { /// 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(()); @@ -1791,8 +1737,6 @@ pub fn new + ?Sized>(s: &S) -> &Path { /// Yields the underlying [`OsStr`] slice. /// - /// [`OsStr`]: ../ffi/struct.OsStr.html - /// /// # Examples /// /// ``` @@ -1812,7 +1756,7 @@ pub fn as_os_str(&self) -> &OsStr { /// Note that validation is performed because non-UTF-8 strings are /// perfectly valid for some OS. /// - /// [`&str`]: ../primitive.str.html + /// [`&str`]: str /// /// # Examples /// @@ -1832,8 +1776,8 @@ pub fn to_str(&self) -> Option<&str> { /// Any non-Unicode sequences are replaced with /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. /// - /// [`Cow`]: ../borrow/enum.Cow.html - /// [U+FFFD]: ../char/constant.REPLACEMENT_CHARACTER.html + /// [`Cow`]: Cow + /// [U+FFFD]: super::char::REPLACEMENT_CHARACTER /// /// # Examples /// @@ -1855,8 +1799,6 @@ pub fn to_string_lossy(&self) -> Cow<'_, str> { /// Converts a `Path` to an owned [`PathBuf`]. /// - /// [`PathBuf`]: struct.PathBuf.html - /// /// # Examples /// /// ``` @@ -1888,7 +1830,7 @@ pub fn to_path_buf(&self) -> PathBuf { /// 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 { @@ -1912,7 +1854,7 @@ 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() @@ -1947,8 +1889,6 @@ pub fn has_root(&self) -> bool { /// /// Returns [`None`] if the path terminates in a root or prefix. /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// /// # Examples /// /// ``` @@ -1992,10 +1932,16 @@ pub fn parent(&self) -> Option<&Path> { /// 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) } @@ -2008,8 +1954,6 @@ pub fn ancestors(&self) -> Ancestors<'_> { /// /// Returns [`None`] if the path terminates in `..`. /// - /// [`None`]: ../../std/option/enum.Option.html#variant.None - /// /// # Examples /// /// ``` @@ -2038,8 +1982,7 @@ pub fn file_name(&self) -> Option<&OsStr> { /// 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 /// @@ -2053,8 +1996,9 @@ pub fn file_name(&self) -> Option<&OsStr> { /// 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"))); @@ -2124,7 +2068,7 @@ fn _ends_with(&self, child: &Path) -> 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: /// @@ -2133,16 +2077,13 @@ fn _ends_with(&self, child: &Path) -> bool { /// * 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> { @@ -2158,17 +2099,15 @@ 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> { @@ -2179,9 +2118,6 @@ 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 /// /// ``` @@ -2205,9 +2141,6 @@ fn _join(&self, path: &Path) -> PathBuf { /// /// See [`PathBuf::set_file_name`] for more details. /// - /// [`PathBuf`]: struct.PathBuf.html - /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name - /// /// # Examples /// /// ``` @@ -2234,9 +2167,6 @@ fn _with_file_name(&self, file_name: &OsStr) -> PathBuf { /// /// See [`PathBuf::set_extension`] for more details. /// - /// [`PathBuf`]: struct.PathBuf.html - /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension - /// /// # Examples /// /// ``` @@ -2247,6 +2177,8 @@ fn _with_file_name(&self, file_name: &OsStr) -> PathBuf { /// /// 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>(&self, extension: S) -> PathBuf { @@ -2291,8 +2223,7 @@ fn _with_extension(&self, extension: &OsStr) -> 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()); @@ -2312,8 +2243,7 @@ pub fn components(&self) -> Components<'_> { /// 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 /// @@ -2335,7 +2265,7 @@ pub fn iter(&self) -> Iter<'_> { /// 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 /// @@ -2358,8 +2288,6 @@ pub fn display(&self) -> Display<'_> { /// /// This is an alias to [`fs::metadata`]. /// - /// [`fs::metadata`]: ../fs/fn.metadata.html - /// /// # Examples /// /// ```no_run @@ -2378,8 +2306,6 @@ pub fn metadata(&self) -> io::Result { /// /// This is an alias to [`fs::symlink_metadata`]. /// - /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html - /// /// # Examples /// /// ```no_run @@ -2399,8 +2325,6 @@ pub fn symlink_metadata(&self) -> io::Result { /// /// This is an alias to [`fs::canonicalize`]. /// - /// [`fs::canonicalize`]: ../fs/fn.canonicalize.html - /// /// # Examples /// /// ```no_run @@ -2418,8 +2342,6 @@ pub fn canonicalize(&self) -> io::Result { /// /// This is an alias to [`fs::read_link`]. /// - /// [`fs::read_link`]: ../fs/fn.read_link.html - /// /// # Examples /// /// ```no_run @@ -2435,15 +2357,11 @@ pub fn read_link(&self) -> io::Result { /// 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 @@ -2473,15 +2391,13 @@ pub fn read_dir(&self) -> io::Result { /// /// ```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() @@ -2506,20 +2422,14 @@ pub fn exists(&self) -> bool { /// # 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) @@ -2544,11 +2454,8 @@ pub fn is_file(&self) -> bool { /// # 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) @@ -2556,9 +2463,6 @@ pub fn is_dir(&self) -> bool { /// Converts a [`Box`][`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) -> PathBuf { let rw = Box::into_raw(self) as *mut OsStr; @@ -2597,10 +2501,8 @@ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { /// 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, diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index fb825ab16eb..45af9f68a0f 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -48,9 +48,7 @@ fn lang_start_internal( 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 @@ -64,5 +62,9 @@ fn lang_start( 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, + ) } diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs index 675b82ceb77..8eaf07e52d6 100644 --- a/library/std/src/sys/hermit/mod.rs +++ b/library/std/src/sys/hermit/mod.rs @@ -106,7 +106,7 @@ pub fn init() { 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; } diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs index e11afed6687..7bd71e120de 100644 --- a/library/std/src/sys/hermit/thread.rs +++ b/library/std/src/sys/hermit/thread.rs @@ -4,7 +4,7 @@ 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; diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 84c4d662161..ba169b251b0 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -3,6 +3,8 @@ use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; use crate::mem; +#[cfg(not(any(target_os = "redox", target_env = "newlib")))] +use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::cvt; use crate::sys_common::AsInner; @@ -26,6 +28,27 @@ pub struct FileDesc { #[cfg(not(target_os = "macos"))] const READ_LIMIT: usize = libc::ssize_t::MAX as usize; +#[cfg(not(any(target_os = "redox", target_env = "newlib")))] +fn max_iov() -> usize { + static LIM: AtomicUsize = AtomicUsize::new(0); + + let mut lim = LIM.load(Ordering::Relaxed); + if lim == 0 { + let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) }; + + // 16 is the minimum value required by POSIX. + lim = if ret > 0 { ret as usize } else { 16 }; + LIM.store(lim, Ordering::Relaxed); + } + + lim +} + +#[cfg(any(target_os = "redox", target_env = "newlib"))] +fn max_iov() -> usize { + 16 // The minimum value required by POSIX. +} + impl FileDesc { pub fn new(fd: c_int) -> FileDesc { FileDesc { fd } @@ -54,7 +77,7 @@ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result { libc::readv( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, + cmp::min(bufs.len(), max_iov()) as c_int, ) })?; Ok(ret as usize) @@ -111,7 +134,7 @@ pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result { libc::writev( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::MAX as usize) as c_int, + cmp::min(bufs.len(), max_iov()) as c_int, ) })?; Ok(ret as usize) @@ -256,3 +279,16 @@ fn drop(&mut self) { let _ = unsafe { libc::close(self.fd) }; } } + +#[cfg(test)] +mod tests { + use super::{FileDesc, IoSlice}; + use core::mem::ManuallyDrop; + + #[test] + fn limit_vector_count() { + let stdout = ManuallyDrop::new(FileDesc { fd: 1 }); + let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); + assert!(stdout.write_vectored(&bufs).is_ok()); + } +} diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index 9a52371280e..982ec912c44 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -99,43 +99,28 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option { 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 diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index d386a656e4f..1c5fbf7d701 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -74,6 +74,8 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: 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; @@ -89,16 +91,24 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: 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; @@ -123,10 +133,29 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: pub fn __rust_begin_short_backtrace(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: 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 { diff --git a/library/test/src/helpers/concurrency.rs b/library/test/src/helpers/concurrency.rs index 2fe87247e3a..7ca27bf0dc1 100644 --- a/library/test/src/helpers/concurrency.rs +++ b/library/test/src/helpers/concurrency.rs @@ -4,7 +4,7 @@ #[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 = s.parse().ok(); match opt_n { @@ -13,7 +13,7 @@ pub fn get_concurrency() -> usize { } } Err(..) => num_cpus(), - }; + } } cfg_if::cfg_if! { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 933b647071f..6bd708ef487 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -514,7 +514,10 @@ fn run_test_inner( /// Fixed frame used to clean the backtrace with `RUST_BACKTRACE=1`. #[inline(never)] fn __rust_begin_short_backtrace(f: F) { - f() + f(); + + // prevent this frame from being tail-call optimised away + black_box(()); } fn run_test_in_process( diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index c4d10ab177b..20a2ca98405 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -19,6 +19,7 @@ } else if #[cfg(any( unix, windows, + target_os = "psp", target_os = "cloudabi", all(target_vendor = "fortanix", target_env = "sgx"), ))] { @@ -32,7 +33,6 @@ // - os=uefi // - os=cuda // - nvptx64-nvidia-cuda - // - mipsel-sony-psp // - Any new targets not listed above. } } diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 8a6973bcdd6..0ff77de003d 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -587,6 +587,7 @@ jobs: <<: [*shared-ci-variables, *dummy-variables] if: github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust' strategy: + fail-fast: false matrix: include: ############################# diff --git a/src/doc/book b/src/doc/book index a914f2c7e5c..363293c1c5c 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit a914f2c7e5cdb771fa465de142381a51c53b580e +Subproject commit 363293c1c5ce9e84ea3935a5e29ce8624801208a diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 94d9ea8460b..b5256448a2a 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 94d9ea8460bcbbbfef1877b47cb930260b5849a7 +Subproject commit b5256448a2a4c1bec68b93c0847066f92f2ff5a9 diff --git a/src/doc/reference b/src/doc/reference index b329ce37424..c9b2736a059 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit b329ce37424874ad4db94f829a55807c6e21d2cb +Subproject commit c9b2736a059469043177e1e4ed41a55d7c63ac28 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 229c6945a26..2e9271981ad 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 229c6945a26a53a751ffa4f9cb418388c00029d3 +Subproject commit 2e9271981adc32613365810f3428334c07095215 diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index cec9c56a235..67f99ec4e40 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -352,8 +352,13 @@ class StdHashMapProvider: 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): @@ -374,6 +379,8 @@ class StdHashMapProvider: 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] diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 3c7817b3a61..19da75c35b4 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -514,6 +514,8 @@ class StdHashMapSyntheticProvider: # 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: @@ -529,10 +531,15 @@ class StdHashMapSyntheticProvider: 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() diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index b3fc3d17af7..4e81173d3d0 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -30,6 +30,7 @@ base.table.items base.table.items + base.table.growth_left + base.hash_builder @@ -40,7 +41,7 @@ n-- - base.table.data.pointer[i].__1 + static_cast<tuple<$T1, $T2>*>(base.table.ctrl.pointer)[-(i + 1)].__1 i++ @@ -53,6 +54,7 @@ map.base.table.items map.base.table.items + map.base.table.growth_left + map.base.hash_builder @@ -63,36 +65,7 @@ n-- - map.base.table.data.pointer[i].__0 - - i++ - - - - - - - - {{ size={items} }} - - items - items + growth_left - - - - - items - - - - - n-- - data.pointer[i] + static_cast<$T1*>(map.base.table.ctrl.pointer)[-(i + 1)] i++ diff --git a/src/librustc_ast/Cargo.toml b/src/librustc_ast/Cargo.toml index a36f49bd414..ab0ab7244db 100644 --- a/src/librustc_ast/Cargo.toml +++ b/src/librustc_ast/Cargo.toml @@ -12,7 +12,6 @@ doctest = false [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" } diff --git a/src/librustc_ast/ast.rs b/src/librustc_ast/ast.rs index 6543117774a..83a9de84ed8 100644 --- a/src/librustc_ast/ast.rs +++ b/src/librustc_ast/ast.rs @@ -23,7 +23,7 @@ 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}; @@ -378,7 +378,7 @@ fn default() -> Generics { #[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, @@ -1052,6 +1052,30 @@ pub fn returns(&self) -> 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 { match &self.kind { ExprKind::Path(None, path) => Some(GenericBound::Trait( @@ -2365,7 +2389,7 @@ pub enum AttrKind { /// 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. diff --git a/src/librustc_ast/attr/mod.rs b/src/librustc_ast/attr/mod.rs index 809fda86542..edcbce3e2cf 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/src/librustc_ast/attr/mod.rs @@ -7,75 +7,33 @@ 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>, - known_attrs: Lock>, - span_session_globals: rustc_span::SessionGlobals, -} +pub struct MarkedAttrs(GrowableBitSet); -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(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(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 { @@ -169,23 +127,8 @@ impl Attribute { 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`. @@ -198,7 +141,7 @@ pub fn ident(&self) -> Option { None } } - AttrKind::DocComment(_) => None, + AttrKind::DocComment(..) => None, } } pub fn name_or_empty(&self) -> Symbol { @@ -218,7 +161,7 @@ pub fn meta_item_list(&self) -> Option> { Some(MetaItem { kind: MetaItemKind::List(list), .. }) => Some(list), _ => None, }, - AttrKind::DocComment(_) => None, + AttrKind::DocComment(..) => None, } } @@ -314,13 +257,13 @@ impl Attribute { 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 { 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()) } @@ -331,14 +274,14 @@ pub fn doc_str(&self) -> Option { 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"), } } @@ -405,30 +348,19 @@ pub fn mk_attr_outer(item: MetaItem) -> Attribute { 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 { - attrs.iter().filter(move |attr| attr.check_name(name)) -} - -pub fn first_attr_value_str_by_name(attrs: &[Attribute], name: Symbol) -> Option { - attrs.iter().find(|at| at.check_name(name)).and_then(|at| at.value_str()) -} - impl MetaItem { fn token_trees_and_joints(&self) -> Vec { let mut idents = vec![]; diff --git a/src/librustc_ast/entry.rs b/src/librustc_ast/entry.rs index 90d417a45fd..290f6006de0 100644 --- a/src/librustc_ast/entry.rs +++ b/src/librustc_ast/entry.rs @@ -1,7 +1,3 @@ -use crate::ast::{Item, ItemKind}; -use crate::attr; -use rustc_span::symbol::sym; - pub enum EntryPointType { None, MainNamed, @@ -9,27 +5,3 @@ pub enum EntryPointType { 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, - } -} diff --git a/src/librustc_ast/expand/allocator.rs b/src/librustc_ast/expand/allocator.rs index 7c67f029f38..cd27f958e46 100644 --- a/src/librustc_ast/expand/allocator.rs +++ b/src/librustc_ast/expand/allocator.rs @@ -1,6 +1,4 @@ -use crate::{ast, attr, visit}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; #[derive(Clone, Copy)] pub enum AllocatorKind { @@ -53,25 +51,3 @@ pub struct AllocatorMethod { output: AllocatorTy::ResultPtr, }, ]; - -pub fn global_allocator_spans(krate: &ast::Crate) -> Vec { - struct Finder { - name: Symbol, - spans: Vec, - } - 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 -} diff --git a/src/librustc_ast/expand/mod.rs b/src/librustc_ast/expand/mod.rs index 3c634ff40cc..eebfc38bdf4 100644 --- a/src/librustc_ast/expand/mod.rs +++ b/src/librustc_ast/expand/mod.rs @@ -1,12 +1,3 @@ //! 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)) -} diff --git a/src/librustc_ast/lib.rs b/src/librustc_ast/lib.rs index ca68db0b9f6..3f876169d22 100644 --- a/src/librustc_ast/lib.rs +++ b/src/librustc_ast/lib.rs @@ -42,7 +42,6 @@ pub mod util { 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; diff --git a/src/librustc_ast/mut_visit.rs b/src/librustc_ast/mut_visit.rs index 54f81ef106f..df6e8218f6c 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/src/librustc_ast/mut_visit.rs @@ -582,7 +582,7 @@ pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { vis.visit_path(path); visit_mac_args(args, vis); } - AttrKind::DocComment(_) => {} + AttrKind::DocComment(..) => {} } vis.visit_span(span); } diff --git a/src/librustc_ast/token.rs b/src/librustc_ast/token.rs index e1c94ddf782..bcce881ed48 100644 --- a/src/librustc_ast/token.rs +++ b/src/librustc_ast/token.rs @@ -17,6 +17,12 @@ 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 { @@ -238,9 +244,10 @@ pub enum TokenKind { Interpolated(Lrc), - // 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 diff --git a/src/librustc_ast/util/comments.rs b/src/librustc_ast/util/comments.rs index 39921b20226..a73891db160 100644 --- a/src/librustc_ast/util/comments.rs +++ b/src/librustc_ast/util/comments.rs @@ -1,11 +1,7 @@ -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; @@ -28,43 +24,48 @@ pub struct Comment { 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 { + 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 { + 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) -> Vec { let mut i = 0; @@ -126,26 +127,15 @@ fn horizontal_trim(lines: Vec) -> Vec { } } - // 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::>(); - + let data = data.as_str(); + if data.contains('\n') { + let lines = data.lines().map(|s| s.to_string()).collect::>(); 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. @@ -203,7 +193,7 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec Vec { - 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. @@ -249,9 +239,13 @@ pub fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec { - 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), }) diff --git a/src/librustc_ast/util/comments/tests.rs b/src/librustc_ast/util/comments/tests.rs index f08011fe4f8..1919b9341aa 100644 --- a/src/librustc_ast/util/comments/tests.rs +++ b/src/librustc_ast/util/comments/tests.rs @@ -1,11 +1,18 @@ 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"); }) } @@ -13,8 +20,8 @@ fn test_block_doc_comment_1() { #[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"); }) } @@ -22,37 +29,22 @@ fn test_block_doc_comment_2() { #[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"); }) } diff --git a/src/librustc_ast/util/lev_distance/tests.rs b/src/librustc_ast/util/lev_distance/tests.rs index 94d56a3d7b4..7ebedbcb76a 100644 --- a/src/librustc_ast/util/lev_distance/tests.rs +++ b/src/librustc_ast/util/lev_distance/tests.rs @@ -21,7 +21,7 @@ fn test_lev_distance() { #[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!( diff --git a/src/librustc_ast/visit.rs b/src/librustc_ast/visit.rs index ccab46703df..2c3d1e97df9 100644 --- a/src/librustc_ast/visit.rs +++ b/src/librustc_ast/visit.rs @@ -880,7 +880,7 @@ pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { 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(..) => {} } } diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index abd5df537db..f9e54903a66 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -1067,7 +1067,7 @@ fn lower_expr_asm(&mut self, sp: Span, asm: &InlineAsm) -> hir::ExprKind<'hir> { .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; } diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index 5414e584290..5186e62fbf9 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -3,7 +3,6 @@ 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}; @@ -205,7 +204,7 @@ pub fn lower_item(&mut self, i: &Item) -> Option> { 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 { diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 9df7ad2a9ac..49bbd50db57 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -37,7 +37,6 @@ 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}; @@ -981,7 +980,7 @@ fn lower_attr(&mut self, attr: &Attribute) -> Attribute { 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 } @@ -2215,7 +2214,7 @@ fn lower_generic_param( 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(), }; @@ -2236,7 +2235,7 @@ fn lower_generic_param( 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, diff --git a/src/librustc_ast_passes/ast_validation.rs b/src/librustc_ast_passes/ast_validation.rs index daf3e23d6a1..45a026d4b53 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/src/librustc_ast_passes/ast_validation.rs @@ -8,8 +8,6 @@ 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; @@ -776,7 +774,13 @@ fn validate_generic_param_order<'a>( 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, @@ -891,11 +895,11 @@ fn visit_lifetime(&mut self, lifetime: &'a Lifetime) { } 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); } @@ -1027,7 +1031,7 @@ fn visit_item(&mut self, item: &'a Item) { } 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); } } diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index 22eaca4f071..ce39ceff8f3 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -1,11 +1,11 @@ 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; @@ -13,28 +13,32 @@ 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, } @@ -138,6 +142,7 @@ fn check_abi(&self, abi: ast::StrLit) { ); } abi => self + .sess .parse_sess .span_diagnostic .delay_span_bug(span, &format!("unrecognized ABI not caught in lowering: {}", abi)), @@ -167,7 +172,7 @@ fn maybe_report_invalid_custom_discriminants(&self, variants: &[ast::Variant]) { 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", @@ -240,7 +245,7 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) { 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) { @@ -266,7 +271,7 @@ fn visit_name(&mut self, sp: Span, name: Symbol) { 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" ); } @@ -281,7 +286,7 @@ fn visit_item(&mut self, i: &'a ast::Item) { } 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, @@ -289,7 +294,7 @@ fn visit_item(&mut self, i: &'a ast::Item) { "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, @@ -299,7 +304,7 @@ fn visit_item(&mut self, i: &'a ast::Item) { over time" ); } - if attr::contains_name(&i.attrs[..], sym::main) { + if self.sess.contains_name(&i.attrs[..], sym::main) { gate_feature_post!( &self, main, @@ -312,7 +317,7 @@ fn visit_item(&mut self, i: &'a ast::Item) { } 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!( @@ -391,7 +396,7 @@ fn visit_item(&mut self, i: &'a ast::Item) { 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, @@ -450,7 +455,7 @@ fn visit_expr(&mut self, e: &'a ast::Expr) { 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, @@ -526,12 +531,13 @@ fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) { 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) } @@ -599,16 +605,11 @@ fn visit_vis(&mut self, vis: &'a ast::Visibility) { } } -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![]) { @@ -651,18 +652,18 @@ macro_rules! gate_all { 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", diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 4b228629ad7..9d9ca78de55 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -8,10 +8,11 @@ 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}; @@ -50,17 +51,17 @@ impl PpAnn for NoAnn {} pub struct Comments<'a> { sm: &'a SourceMap, - comments: Vec, + comments: Vec, 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 { + pub fn next(&self) -> Option { self.comments.get(self.current).cloned() } @@ -68,9 +69,9 @@ pub fn trailing_comment( &mut self, span: rustc_span::Span, next_pos: Option, - ) -> Option { + ) -> Option { 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()); @@ -152,8 +153,8 @@ pub fn to_string(f: impl FnOnce(&mut State<'_>)) -> String { // 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 { @@ -194,6 +195,19 @@ fn binop_to_string(op: BinOpToken) -> &'static str { } } +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 { @@ -271,7 +285,9 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option) 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 => "".to_string(), token::Whitespace => " ".to_string(), token::Comment => "/* */".to_string(), @@ -447,9 +463,9 @@ fn maybe_print_comment(&mut self, pos: BytePos) { } } - 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(); } @@ -468,7 +484,7 @@ fn print_comment(&mut self, cmnt: &comments::Comment) { } 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 @@ -479,7 +495,7 @@ fn print_comment(&mut self, cmnt: &comments::Comment) { self.hardbreak(); } } - comments::Trailing => { + CommentStyle::Trailing => { if !self.is_beginning_of_line() { self.word(" "); } @@ -497,7 +513,7 @@ fn print_comment(&mut self, cmnt: &comments::Comment) { 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, @@ -516,7 +532,7 @@ fn print_comment(&mut self, cmnt: &comments::Comment) { } } - fn next_comment(&mut self) -> Option { + fn next_comment(&mut self) -> Option { self.comments().as_mut().and_then(|c| c.next()) } @@ -599,8 +615,8 @@ fn print_attribute_inline(&mut self, attr: &ast::Attribute, is_inline: bool) { 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() } } diff --git a/src/librustc_ast_pretty/pprust/tests.rs b/src/librustc_ast_pretty/pprust/tests.rs index 96377a4ae02..fdbd073255e 100644 --- a/src/librustc_ast_pretty/pprust/tests.rs +++ b/src/librustc_ast_pretty/pprust/tests.rs @@ -1,9 +1,9 @@ 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, diff --git a/src/librustc_attr/builtin.rs b/src/librustc_attr/builtin.rs index 983202aafab..552584bb4d0 100644 --- a/src/librustc_attr/builtin.rs +++ b/src/librustc_attr/builtin.rs @@ -1,13 +1,12 @@ //! 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; @@ -86,9 +85,9 @@ pub enum UnwindAttr { } /// Determine what `#[unwind]` attribute is present in `attrs`, if any. -pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option { +pub fn find_unwind_attr(sess: &Session, attrs: &[Attribute]) -> Option { 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 { @@ -99,19 +98,22 @@ pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Op } } - 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(); } } } @@ -161,22 +163,10 @@ pub fn is_stable(&self) -> bool { } } -/// 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, Option) { @@ -184,7 +174,7 @@ pub fn find_stability( } fn find_stability_generic<'a, I>( - sess: &ParseSess, + sess: &Session, attrs_iter: I, item_sp: Span, ) -> (Option, Option) @@ -197,7 +187,7 @@ fn find_stability_generic<'a, I>( let mut const_stab: Option = 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 ![ @@ -214,7 +204,7 @@ fn find_stability_generic<'a, I>( continue; // not a stability level } - mark_used(attr); + sess.mark_attr_used(attr); let meta = attr.meta(); @@ -230,7 +220,7 @@ fn find_stability_generic<'a, I>( let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { handle_errors( - sess, + &sess.parse_sess, meta.span, AttrError::MultipleItem(pprust::path_to_string(&meta.path)), ); @@ -249,10 +239,18 @@ fn find_stability_generic<'a, I>( 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; } @@ -318,13 +316,13 @@ fn find_stability_generic<'a, I>( 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), @@ -336,7 +334,7 @@ fn find_stability_generic<'a, I>( } } else { handle_errors( - sess, + &sess.parse_sess, meta.span(), AttrError::UnsupportedLiteral("unsupported literal", false), ); @@ -359,7 +357,7 @@ fn find_stability_generic<'a, I>( } } (None, _, _) => { - handle_errors(sess, attr.span, AttrError::MissingFeature); + handle_errors(&sess.parse_sess, attr.span, AttrError::MissingFeature); continue; } _ => { @@ -371,10 +369,18 @@ fn find_stability_generic<'a, I>( } 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; } @@ -395,7 +401,7 @@ fn find_stability_generic<'a, I>( } _ => { handle_errors( - sess, + &sess.parse_sess, meta.span(), AttrError::UnknownMetaItem( pprust::path_to_string(&mi.path), @@ -407,7 +413,7 @@ fn find_stability_generic<'a, I>( }, NestedMetaItem::Literal(lit) => { handle_errors( - sess, + &sess.parse_sess, lit.span, AttrError::UnsupportedLiteral("unsupported literal", false), ); @@ -431,11 +437,11 @@ fn find_stability_generic<'a, I>( } } (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; } } @@ -466,8 +472,8 @@ fn find_stability_generic<'a, I>( (stab, const_stab) } -pub fn find_crate_name(attrs: &[Attribute]) -> Option { - super::first_attr_value_str_by_name(attrs, sym::crate_name) +pub fn find_crate_name(sess: &Session, attrs: &[Attribute]) -> Option { + sess.first_attr_value_str_by_name(attrs, sym::crate_name) } /// Tests if a cfg-pattern matches the cfg set @@ -630,16 +636,12 @@ pub struct Deprecation { } /// Finds the deprecation attribute. `None` if none exists. -pub fn find_deprecation( - sess: &ParseSess, - attrs: &[Attribute], - item_sp: Span, -) -> Option { +pub fn find_deprecation(sess: &Session, attrs: &[Attribute], item_sp: Span) -> Option { 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 @@ -647,10 +649,11 @@ fn find_deprecation_generic<'a, I>( I: Iterator, { let mut depr: Option = 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; } @@ -673,7 +676,7 @@ fn find_deprecation_generic<'a, I>( let get = |meta: &MetaItem, item: &mut Option| { if item.is_some() { handle_errors( - sess, + &sess.parse_sess, meta.span, AttrError::MultipleItem(pprust::path_to_string(&meta.path)), ); @@ -685,7 +688,7 @@ fn find_deprecation_generic<'a, I>( } else { if let Some(lit) = meta.name_value_literal() { handle_errors( - sess, + &sess.parse_sess, lit.span, AttrError::UnsupportedLiteral( "literal in `deprecated` \ @@ -710,28 +713,28 @@ fn find_deprecation_generic<'a, I>( 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"] @@ -743,7 +746,7 @@ fn find_deprecation_generic<'a, I>( }, NestedMetaItem::Literal(lit) => { handle_errors( - sess, + &sess.parse_sess, lit.span, AttrError::UnsupportedLiteral( "item in `deprecated` must be a key/value pair", @@ -757,13 +760,13 @@ fn find_deprecation_generic<'a, I>( } } - 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; } @@ -773,9 +776,9 @@ fn find_deprecation_generic<'a, I>( } } - 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 }); } @@ -818,18 +821,18 @@ pub fn is_signed(self) -> bool { /// 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 { +pub fn find_repr_attrs(sess: &Session, attr: &Attribute) -> Vec { 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", @@ -973,13 +976,14 @@ pub enum TransparencyError { } pub fn find_transparency( + sess: &Session, attrs: &[Attribute], macro_rules: bool, ) -> (Transparency, Option) { 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; @@ -1004,18 +1008,20 @@ pub fn find_transparency( } pub fn allow_internal_unstable<'a>( + sess: &'a Session, attrs: &[Attribute], - diag: &'a rustc_errors::Handler, ) -> Option + '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 })) diff --git a/src/librustc_builtin_macros/cfg.rs b/src/librustc_builtin_macros/cfg.rs index 3c09b26af42..0247ca32991 100644 --- a/src/librustc_builtin_macros/cfg.rs +++ b/src/librustc_builtin_macros/cfg.rs @@ -19,7 +19,7 @@ pub fn expand_cfg( 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) => { diff --git a/src/librustc_builtin_macros/cfg_accessible.rs b/src/librustc_builtin_macros/cfg_accessible.rs index 3607a4d0d15..7a91dde5a9d 100644 --- a/src/librustc_builtin_macros/cfg_accessible.rs +++ b/src/librustc_builtin_macros/cfg_accessible.rs @@ -37,7 +37,12 @@ fn expand( ) -> ExpandResult, 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, diff --git a/src/librustc_builtin_macros/deriving/default.rs b/src/librustc_builtin_macros/deriving/default.rs index 8ca1be1efb6..2611855a3a1 100644 --- a/src/librustc_builtin_macros/deriving/default.rs +++ b/src/librustc_builtin_macros/deriving/default.rs @@ -72,7 +72,7 @@ fn default_substructure( }, 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" diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/src/librustc_builtin_macros/deriving/generic/mod.rs index c43d1cf1888..908aabe9024 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/src/librustc_builtin_macros/deriving/generic/mod.rs @@ -392,7 +392,7 @@ pub fn expand_ext( 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; } @@ -677,7 +677,7 @@ fn create_derived_impl( 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( diff --git a/src/librustc_builtin_macros/env.rs b/src/librustc_builtin_macros/env.rs index 6c3a1ce0958..b6f733ee93d 100644 --- a/src/librustc_builtin_macros/env.rs +++ b/src/librustc_builtin_macros/env.rs @@ -23,7 +23,7 @@ pub fn expand_option_env<'cx>( 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)); @@ -81,7 +81,7 @@ pub fn expand_env<'cx>( 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()); diff --git a/src/librustc_builtin_macros/global_allocator.rs b/src/librustc_builtin_macros/global_allocator.rs index 89446a1aa96..ccff8aa90a8 100644 --- a/src/librustc_builtin_macros/global_allocator.rs +++ b/src/librustc_builtin_macros/global_allocator.rs @@ -19,7 +19,7 @@ pub fn expand( 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 { diff --git a/src/librustc_builtin_macros/llvm_asm.rs b/src/librustc_builtin_macros/llvm_asm.rs index 0f4efc153b9..77fd71d58ef 100644 --- a/src/librustc_builtin_macros/llvm_asm.rs +++ b/src/librustc_builtin_macros/llvm_asm.rs @@ -110,7 +110,7 @@ fn parse_inline_asm<'a>( // 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" @@ -171,7 +171,7 @@ fn parse_inline_asm<'a>( 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 '+'" @@ -201,7 +201,7 @@ fn parse_inline_asm<'a>( 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 '='" @@ -209,7 +209,7 @@ fn parse_inline_asm<'a>( .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 '+'" @@ -236,7 +236,7 @@ fn parse_inline_asm<'a>( 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" diff --git a/src/librustc_builtin_macros/proc_macro_harness.rs b/src/librustc_builtin_macros/proc_macro_harness.rs index 763bdca35eb..4f2f066e652 100644 --- a/src/librustc_builtin_macros/proc_macro_harness.rs +++ b/src/librustc_builtin_macros/proc_macro_harness.rs @@ -2,13 +2,12 @@ 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}; @@ -42,6 +41,7 @@ enum ProcMacro { } struct CollectProcMacros<'a> { + sess: &'a Session, macros: Vec, in_root: bool, handler: &'a rustc_errors::Handler, @@ -51,7 +51,7 @@ struct CollectProcMacros<'a> { } pub fn inject( - sess: &ParseSess, + sess: &Session, resolver: &mut dyn ResolverExpand, mut krate: ast::Crate, is_proc_macro_crate: bool, @@ -64,6 +64,7 @@ pub fn inject( let mut cx = ExtCtxt::new(sess, ecfg, resolver, None); let mut collect = CollectProcMacros { + sess, macros: Vec::new(), in_root: true, handler, @@ -244,7 +245,7 @@ fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { 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); @@ -263,7 +264,7 @@ fn visit_item(&mut self, item: &'a ast::Item) { 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(); @@ -331,11 +332,11 @@ fn visit_item(&mut self, item: &'a ast::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); }; diff --git a/src/librustc_builtin_macros/standard_library_imports.rs b/src/librustc_builtin_macros/standard_library_imports.rs index 671ff8ce54f..52759fede75 100644 --- a/src/librustc_builtin_macros/standard_library_imports.rs +++ b/src/librustc_builtin_macros/standard_library_imports.rs @@ -1,8 +1,8 @@ +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}; @@ -11,16 +11,16 @@ pub fn inject( mut krate: ast::Crate, resolver: &mut dyn ResolverExpand, - sess: &ParseSess, + sess: &Session, alt_std_name: Option, ) -> (ast::Crate, Option) { - 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] diff --git a/src/librustc_builtin_macros/test.rs b/src/librustc_builtin_macros/test.rs index 29095034ba9..16a95288ee8 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/src/librustc_builtin_macros/test.rs @@ -6,6 +6,7 @@ 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; @@ -87,7 +88,7 @@ pub fn expand_test_or_bench( }; 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.", ); @@ -232,9 +233,15 @@ pub fn expand_test_or_bench( ), ), // 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", @@ -318,18 +325,18 @@ enum ShouldPanic { Yes(Option), } -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")] @@ -393,8 +400,8 @@ fn test_type(cx: &ExtCtxt<'_>) -> TestType { } 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") @@ -453,7 +460,7 @@ fn has_bench_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool { }; 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`", diff --git a/src/librustc_builtin_macros/test_harness.rs b/src/librustc_builtin_macros/test_harness.rs index 98c5c6936d7..b21a7c1e4d5 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/src/librustc_builtin_macros/test_harness.rs @@ -3,13 +3,13 @@ use log::debug; 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}; @@ -35,41 +35,35 @@ struct TestCtxt<'a> { // 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, @@ -79,7 +73,7 @@ pub fn inject( resolver, reexport_test_harness_main, krate, - features, + &sess.features_untracked(), panic_strategy, test_runner, ) @@ -101,7 +95,7 @@ fn visit_crate(&mut self, c: &mut ast::Crate) { fn flat_map_item(&mut self, i: P) -> SmallVec<[P; 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 }; @@ -143,15 +137,39 @@ fn visit_mac(&mut self, _mac: &mut ast::MacCall) { } } +// 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) -> SmallVec<[P; 1]> { self.depth += 1; let item = noop_flat_map_item(i, self).expect_one("noop did something"); @@ -160,7 +178,7 @@ impl MutVisitor for EntryPointCleaner { // 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); @@ -170,7 +188,10 @@ impl MutVisitor for EntryPointCleaner { 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(); @@ -189,7 +210,7 @@ fn visit_mac(&mut self, _mac: &mut ast::MacCall) { /// 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, krate: &mut ast::Crate, @@ -211,7 +232,7 @@ fn generate_test_harness( 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 { @@ -339,12 +360,16 @@ fn mk_tests_slice(cx: &TestCtxt<'_>, sp: Span) -> P { ) } -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 { - 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 { + 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 { diff --git a/src/librustc_builtin_macros/util.rs b/src/librustc_builtin_macros/util.rs index b486eadd1a8..3ee6cd73964 100644 --- a/src/librustc_builtin_macros/util.rs +++ b/src/librustc_builtin_macros/util.rs @@ -8,5 +8,5 @@ pub fn check_builtin_macro_attribute(ecx: &ExtCtxt<'_>, meta_item: &MetaItem, na // 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); } diff --git a/src/librustc_codegen_llvm/consts.rs b/src/librustc_codegen_llvm/consts.rs index 1288870f55f..acfb294f7c1 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/src/librustc_codegen_llvm/consts.rs @@ -253,7 +253,7 @@ impl CodegenCx<'ll, 'tcx> { 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); } } diff --git a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs b/src/librustc_codegen_llvm/coverageinfo/mapgen.rs index 4d9747a43f2..9d2383abeed 100644 --- a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs +++ b/src/librustc_codegen_llvm/coverageinfo/mapgen.rs @@ -92,7 +92,7 @@ fn new() -> Self { fn write_coverage_mappings( &mut self, expressions: Vec, - counter_regions: impl Iterator, + counter_regions: impl Iterator)>, coverage_mappings_buffer: &RustString, ) { let mut counter_regions = counter_regions.collect::>(); @@ -102,7 +102,7 @@ fn write_coverage_mappings( let mut virtual_file_mapping = Vec::new(); let mut mapping_regions = Vec::new(); - let mut current_file_path = None; + let mut current_file_name = None; let mut current_file_id = 0; // Convert the list of (Counter, Region) pairs to an array of `CounterMappingRegion`, sorted @@ -112,22 +112,22 @@ fn write_coverage_mappings( // `filenames` array. counter_regions.sort_unstable_by_key(|(_counter, region)| *region); for (counter, region) in counter_regions { - let (file_path, start_line, start_col, end_line, end_col) = region.file_start_and_end(); - let same_file = current_file_path.as_ref().map_or(false, |p| p == file_path); + let Region { file_name, start_line, start_col, end_line, end_col } = *region; + let same_file = current_file_name.as_ref().map_or(false, |p| p == file_name); if !same_file { - if current_file_path.is_some() { + if current_file_name.is_some() { current_file_id += 1; } - current_file_path = Some(file_path.clone()); - let filename = CString::new(file_path.to_string_lossy().to_string()) - .expect("null error converting filename to C string"); - debug!(" file_id: {} = '{:?}'", current_file_id, filename); - let filenames_index = match self.filename_to_index.get(&filename) { + current_file_name = Some(file_name.to_string()); + 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(filename.clone()); - self.filename_to_index.insert(filename.clone(), index); + self.filenames.push(c_filename.clone()); + self.filename_to_index.insert(c_filename.clone(), index); index } }; diff --git a/src/librustc_codegen_llvm/coverageinfo/mod.rs b/src/librustc_codegen_llvm/coverageinfo/mod.rs index 9d2090eae8f..7b864e499d1 100644 --- a/src/librustc_codegen_llvm/coverageinfo/mod.rs +++ b/src/librustc_codegen_llvm/coverageinfo/mod.rs @@ -6,7 +6,7 @@ use libc::c_uint; use llvm::coverageinfo::CounterMappingRegion; use log::debug; -use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage}; +use rustc_codegen_ssa::coverageinfo::map::{CounterExpression, ExprKind, FunctionCoverage, Region}; use rustc_codegen_ssa::traits::{ BaseTypeMethods, CoverageInfoBuilderMethods, CoverageInfoMethods, StaticMethods, }; @@ -49,19 +49,18 @@ fn add_counter_region( instance: Instance<'tcx>, function_source_hash: u64, id: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ) { debug!( "adding counter to coverage_regions: instance={:?}, function_source_hash={}, id={}, \ - byte range {}..{}", - instance, function_source_hash, id, start_byte_pos, end_byte_pos, + at {:?}", + instance, function_source_hash, id, region, ); let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); coverage_regions .entry(instance) .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_counter(function_source_hash, id, start_byte_pos, end_byte_pos); + .add_counter(function_source_hash, id, region); } fn add_counter_expression_region( @@ -71,43 +70,30 @@ fn add_counter_expression_region( lhs: u32, op: ExprKind, rhs: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ) { debug!( "adding counter expression to coverage_regions: instance={:?}, id={}, {} {:?} {}, \ - byte range {}..{}", - instance, id_descending_from_max, lhs, op, rhs, start_byte_pos, end_byte_pos, + at {:?}", + instance, id_descending_from_max, lhs, op, rhs, region, ); let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); coverage_regions .entry(instance) .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_counter_expression( - id_descending_from_max, - lhs, - op, - rhs, - start_byte_pos, - end_byte_pos, - ); + .add_counter_expression(id_descending_from_max, lhs, op, rhs, region); } - fn add_unreachable_region( - &mut self, - instance: Instance<'tcx>, - start_byte_pos: u32, - end_byte_pos: u32, - ) { + fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'tcx>) { debug!( - "adding unreachable code to coverage_regions: instance={:?}, byte range {}..{}", - instance, start_byte_pos, end_byte_pos, + "adding unreachable code to coverage_regions: instance={:?}, at {:?}", + instance, region, ); let mut coverage_regions = self.coverage_context().function_coverage_map.borrow_mut(); coverage_regions .entry(instance) .or_insert_with(|| FunctionCoverage::new(self.tcx, instance)) - .add_unreachable_region(start_byte_pos, end_byte_pos); + .add_unreachable_region(region); } } diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/src/librustc_codegen_llvm/debuginfo/gdb.rs index 64d4076cbf0..29edd66049c 100644 --- a/src/librustc_codegen_llvm/debuginfo/gdb.rs +++ b/src/librustc_codegen_llvm/debuginfo/gdb.rs @@ -9,7 +9,6 @@ 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 @@ -61,8 +60,10 @@ pub fn get_or_insert_gdb_debug_scripts_section_global(cx: &CodegenCx<'ll, '_>) - } 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 diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/src/librustc_codegen_llvm/debuginfo/metadata.rs index 6ae7c7efaee..9d6b15ec4af 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/src/librustc_codegen_llvm/debuginfo/metadata.rs @@ -960,7 +960,7 @@ fn pointer_type_metadata( 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(), @@ -968,7 +968,7 @@ fn param_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { Size::ZERO.bits(), DW_ATE_unsigned, ) - }; + } } pub fn compile_unit_metadata( diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index e3a308181b6..dfd5104a31f 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -13,7 +13,7 @@ use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; -use rustc_codegen_ssa::coverageinfo::ExprKind; +use rustc_codegen_ssa::coverageinfo; use rustc_codegen_ssa::glue; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; @@ -93,64 +93,64 @@ fn is_codegen_intrinsic( let mut is_codegen_intrinsic = true; // Set `is_codegen_intrinsic` to `false` to bypass `codegen_intrinsic_call()`. - if self.tcx.sess.opts.debugging_opts.instrument_coverage { - // If the intrinsic is from the local MIR, add the coverage information to the Codegen - // context, to be encoded into the local crate's coverage map. - if caller_instance.def_id().is_local() { - // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with - // external crate dependencies, where: - // 1. Both binary and dependent crates are compiled with `-Zinstrument-coverage` - // 2. Only binary is compiled with `-Zinstrument-coverage` - // 3. Only dependent crates are compiled with `-Zinstrument-coverage` - match intrinsic { - sym::count_code_region => { - use coverage::count_code_region_args::*; - self.add_counter_region( - caller_instance, - op_to_u64(&args[FUNCTION_SOURCE_HASH]), - op_to_u32(&args[COUNTER_ID]), - op_to_u32(&args[START_BYTE_POS]), - op_to_u32(&args[END_BYTE_POS]), - ); - } - sym::coverage_counter_add | sym::coverage_counter_subtract => { - use coverage::coverage_counter_expression_args::*; - self.add_counter_expression_region( - caller_instance, - op_to_u32(&args[EXPRESSION_ID]), - op_to_u32(&args[LEFT_ID]), - if intrinsic == sym::coverage_counter_add { - ExprKind::Add - } else { - ExprKind::Subtract - }, - op_to_u32(&args[RIGHT_ID]), - op_to_u32(&args[START_BYTE_POS]), - op_to_u32(&args[END_BYTE_POS]), - ); - } - sym::coverage_unreachable => { - use coverage::coverage_unreachable_args::*; - self.add_unreachable_region( - caller_instance, - op_to_u32(&args[START_BYTE_POS]), - op_to_u32(&args[END_BYTE_POS]), - ); - } - _ => {} - } + // FIXME(richkadel): Make sure to add coverage analysis tests on a crate with + // external crate dependencies, where: + // 1. Both binary and dependent crates are compiled with `-Zinstrument-coverage` + // 2. Only binary is compiled with `-Zinstrument-coverage` + // 3. Only dependent crates are compiled with `-Zinstrument-coverage` + match intrinsic { + sym::count_code_region => { + use coverage::count_code_region_args::*; + self.add_counter_region( + caller_instance, + op_to_u64(&args[FUNCTION_SOURCE_HASH]), + op_to_u32(&args[COUNTER_ID]), + coverageinfo::Region::new( + op_to_str_slice(&args[FILE_NAME]), + op_to_u32(&args[START_LINE]), + op_to_u32(&args[START_COL]), + op_to_u32(&args[END_LINE]), + op_to_u32(&args[END_COL]), + ), + ); } - - // Only the `count_code_region` coverage intrinsic is translated into an actual LLVM - // intrinsic call (local or not); otherwise, set `is_codegen_intrinsic` to `false`. - match intrinsic { - sym::coverage_counter_add - | sym::coverage_counter_subtract - | sym::coverage_unreachable => { - is_codegen_intrinsic = false; - } - _ => {} + sym::coverage_counter_add | sym::coverage_counter_subtract => { + is_codegen_intrinsic = false; + use coverage::coverage_counter_expression_args::*; + self.add_counter_expression_region( + caller_instance, + op_to_u32(&args[EXPRESSION_ID]), + op_to_u32(&args[LEFT_ID]), + if intrinsic == sym::coverage_counter_add { + coverageinfo::ExprKind::Add + } else { + coverageinfo::ExprKind::Subtract + }, + op_to_u32(&args[RIGHT_ID]), + coverageinfo::Region::new( + op_to_str_slice(&args[FILE_NAME]), + op_to_u32(&args[START_LINE]), + op_to_u32(&args[START_COL]), + op_to_u32(&args[END_LINE]), + op_to_u32(&args[END_COL]), + ), + ); } + sym::coverage_unreachable => { + is_codegen_intrinsic = false; + use coverage::coverage_unreachable_args::*; + self.add_unreachable_region( + caller_instance, + coverageinfo::Region::new( + op_to_str_slice(&args[FILE_NAME]), + op_to_u32(&args[START_LINE]), + op_to_u32(&args[START_COL]), + op_to_u32(&args[END_LINE]), + op_to_u32(&args[END_COL]), + ), + ); + } + _ => {} } is_codegen_intrinsic } @@ -215,9 +215,6 @@ fn codegen_intrinsic_call( self.call(llfn, &[], None) } sym::count_code_region => { - // FIXME(richkadel): The current implementation assumes the MIR for the given - // caller_instance represents a single function. Validate and/or correct if inlining - // and/or monomorphization invalidates these assumptions. let coverageinfo = tcx.coverageinfo(caller_instance.def_id()); let mangled_fn = tcx.symbol_name(caller_instance); let (mangled_fn_name, _len_val) = self.const_str(Symbol::intern(mangled_fn.name)); @@ -2243,6 +2240,10 @@ fn float_type_width(ty: Ty<'_>) -> Option { } } +fn op_to_str_slice<'tcx>(op: &Operand<'tcx>) -> &'tcx str { + Operand::value_from_const(op).try_to_str_slice().expect("Value is &str") +} + fn op_to_u32<'tcx>(op: &Operand<'tcx>) -> u32 { Operand::scalar_from_const(op).to_u32().expect("Scalar is u32") } diff --git a/src/librustc_codegen_ssa/back/write.rs b/src/librustc_codegen_ssa/back/write.rs index b0fae566a5a..7d69bb983dd 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/src/librustc_codegen_ssa/back/write.rs @@ -9,7 +9,6 @@ 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; @@ -416,11 +415,12 @@ pub fn start_async_codegen( 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!( @@ -490,7 +490,7 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir( 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) diff --git a/src/librustc_codegen_ssa/coverageinfo/map.rs b/src/librustc_codegen_ssa/coverageinfo/map.rs index 72138065a90..7f6841f9daa 100644 --- a/src/librustc_codegen_ssa/coverageinfo/map.rs +++ b/src/librustc_codegen_ssa/coverageinfo/map.rs @@ -3,12 +3,8 @@ use rustc_index::vec::IndexVec; use rustc_middle::ty::Instance; use rustc_middle::ty::TyCtxt; -use rustc_span::source_map::{Pos, SourceMap}; -use rustc_span::{BytePos, FileName, Loc, RealFileName}; -use std::cmp::{Ord, Ordering}; -use std::fmt; -use std::path::PathBuf; +use std::cmp::Ord; rustc_index::newtype_index! { pub struct ExpressionOperandId { @@ -38,127 +34,35 @@ pub struct MappedExpressionIndex { } } -#[derive(Clone, Debug)] -pub struct Region { - start: Loc, - end: Loc, -} - -impl Ord for Region { - fn cmp(&self, other: &Self) -> Ordering { - (&self.start.file.name, &self.start.line, &self.start.col, &self.end.line, &self.end.col) - .cmp(&( - &other.start.file.name, - &other.start.line, - &other.start.col, - &other.end.line, - &other.end.col, - )) - } -} - -impl PartialOrd for Region { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for Region { - fn eq(&self, other: &Self) -> bool { - self.start.file.name == other.start.file.name - && self.start.line == other.start.line - && self.start.col == other.start.col - && self.end.line == other.end.line - && self.end.col == other.end.col - } -} - -impl Eq for Region {} - -impl fmt::Display for Region { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (file_path, start_line, start_col, end_line, end_col) = self.file_start_and_end(); - write!(f, "{:?}:{}:{} - {}:{}", file_path, start_line, start_col, end_line, end_col) - } +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub struct Region<'tcx> { + pub file_name: &'tcx str, + pub start_line: u32, + pub start_col: u32, + pub end_line: u32, + pub end_col: u32, } -impl Region { - pub fn new(source_map: &SourceMap, start_byte_pos: u32, end_byte_pos: u32) -> Self { - let start = source_map.lookup_char_pos(BytePos::from_u32(start_byte_pos)); - let end = source_map.lookup_char_pos(BytePos::from_u32(end_byte_pos)); - assert_eq!( - start.file.name, end.file.name, - "Region start ({} -> {:?}) and end ({} -> {:?}) don't come from the same source file!", - start_byte_pos, start, end_byte_pos, end - ); - Self { start, end } - } - - pub fn file_start_and_end<'a>(&'a self) -> (&'a PathBuf, u32, u32, u32, u32) { - let start = &self.start; - let end = &self.end; - match &start.file.name { - FileName::Real(RealFileName::Named(path)) => ( - path, - start.line as u32, - start.col.to_u32() + 1, - end.line as u32, - end.col.to_u32() + 1, - ), - _ => { - bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name) - } - } +impl<'tcx> Region<'tcx> { + pub fn new( + file_name: &'tcx str, + start_line: u32, + start_col: u32, + end_line: u32, + end_col: u32, + ) -> Self { + Self { file_name, start_line, start_col, end_line, end_col } } } #[derive(Clone, Debug)] -pub struct ExpressionRegion { +pub struct ExpressionRegion<'tcx> { lhs: ExpressionOperandId, op: ExprKind, rhs: ExpressionOperandId, - region: Region, + region: Region<'tcx>, } -// FIXME(richkadel): There seems to be a problem computing the file location in -// some cases. I need to investigate this more. When I generate and show coverage -// for the example binary in the crates.io crate `json5format`, I had a couple of -// notable problems: -// -// 1. I saw a lot of coverage spans in `llvm-cov show` highlighting regions in -// various comments (not corresponding to rustdoc code), indicating a possible -// problem with the byte_pos-to-source-map implementation. -// -// 2. And (perhaps not related) when I build the aforementioned example binary with: -// `RUST_FLAGS="-Zinstrument-coverage" cargo build --example formatjson5` -// and then run that binary with -// `LLVM_PROFILE_FILE="formatjson5.profraw" ./target/debug/examples/formatjson5 \ -// some.json5` for some reason the binary generates *TWO* `.profraw` files. One -// named `default.profraw` and the other named `formatjson5.profraw` (the expected -// name, in this case). -// -// 3. I think that if I eliminate regions within a function, their region_ids, -// referenced in expressions, will be wrong? I think the ids are implied by their -// array position in the final coverage map output (IIRC). -// -// 4. I suspect a problem (if not the only problem) is the SourceMap is wrong for some -// region start/end byte positions. Just like I couldn't get the function hash at -// intrinsic codegen time for external crate functions, I think the SourceMap I -// have here only applies to the local crate, and I know I have coverages that -// reference external crates. -// -// I still don't know if I fixed the hash problem correctly. If external crates -// implement the function, can't I use the coverage counters already compiled -// into those external crates? (Maybe not for generics and/or maybe not for -// macros... not sure. But I need to understand this better.) -// -// If the byte range conversion is wrong, fix it. But if it -// is right, then it is possible for the start and end to be in different files. -// Can I do something other than ignore coverages that span multiple files? -// -// If I can resolve this, remove the "Option<>" result type wrapper -// `regions_in_file_order()` accordingly. - /// Collects all of the coverage regions associated with (a) injected counters, (b) counter /// expressions (additions or subtraction), and (c) unreachable regions (always counted as zero), /// for a given Function. Counters and counter expressions have non-overlapping `id`s because they @@ -171,19 +75,17 @@ pub struct ExpressionRegion { /// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count /// for a gap area is only used as the line execution count if there are no other regions on a /// line." -pub struct FunctionCoverage<'a> { - source_map: &'a SourceMap, +pub struct FunctionCoverage<'tcx> { source_hash: u64, - counters: IndexVec>, - expressions: IndexVec>, - unreachable_regions: Vec, + counters: IndexVec>>, + expressions: IndexVec>>, + unreachable_regions: Vec>, } -impl<'a> FunctionCoverage<'a> { - pub fn new<'tcx: 'a>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { +impl<'tcx> FunctionCoverage<'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { let coverageinfo = tcx.coverageinfo(instance.def_id()); Self { - source_map: tcx.sess.source_map(), source_hash: 0, // will be set with the first `add_counter()` counters: IndexVec::from_elem_n(None, coverageinfo.num_counters as usize), expressions: IndexVec::from_elem_n(None, coverageinfo.num_expressions as usize), @@ -194,20 +96,14 @@ pub fn new<'tcx: 'a>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) -> Self { /// Adds a code region to be counted by an injected counter intrinsic. /// The source_hash (computed during coverage instrumentation) should also be provided, and /// should be the same for all counters in a given function. - pub fn add_counter( - &mut self, - source_hash: u64, - id: u32, - start_byte_pos: u32, - end_byte_pos: u32, - ) { + pub fn add_counter(&mut self, source_hash: u64, id: u32, region: Region<'tcx>) { if self.source_hash == 0 { self.source_hash = source_hash; } else { debug_assert_eq!(source_hash, self.source_hash); } self.counters[CounterValueReference::from(id)] - .replace(Region::new(self.source_map, start_byte_pos, end_byte_pos)) + .replace(region) .expect_none("add_counter called with duplicate `id`"); } @@ -231,8 +127,7 @@ pub fn add_counter_expression( lhs: u32, op: ExprKind, rhs: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ) { let expression_id = ExpressionOperandId::from(id_descending_from_max); let lhs = ExpressionOperandId::from(lhs); @@ -240,18 +135,13 @@ pub fn add_counter_expression( let expression_index = self.expression_index(expression_id); self.expressions[expression_index] - .replace(ExpressionRegion { - lhs, - op, - rhs, - region: Region::new(self.source_map, start_byte_pos, end_byte_pos), - }) + .replace(ExpressionRegion { lhs, op, rhs, region }) .expect_none("add_counter_expression called with duplicate `id_descending_from_max`"); } /// Add a region that will be marked as "unreachable", with a constant "zero counter". - pub fn add_unreachable_region(&mut self, start_byte_pos: u32, end_byte_pos: u32) { - self.unreachable_regions.push(Region::new(self.source_map, start_byte_pos, end_byte_pos)); + pub fn add_unreachable_region(&mut self, region: Region<'tcx>) { + self.unreachable_regions.push(region) } /// Return the source hash, generated from the HIR node structure, and used to indicate whether @@ -264,8 +154,8 @@ pub fn source_hash(&self) -> u64 { /// associated `Regions` (from which the LLVM-specific `CoverageMapGenerator` will create /// `CounterMappingRegion`s. pub fn get_expressions_and_counter_regions( - &'a self, - ) -> (Vec, impl Iterator) { + &'tcx self, + ) -> (Vec, impl Iterator)>) { assert!(self.source_hash != 0); let counter_regions = self.counter_regions(); @@ -277,7 +167,7 @@ pub fn get_expressions_and_counter_regions( (counter_expressions, counter_regions) } - fn counter_regions(&'a self) -> impl Iterator { + fn counter_regions(&'tcx self) -> impl Iterator)> { self.counters.iter_enumerated().filter_map(|(index, entry)| { // Option::map() will return None to filter out missing counters. This may happen // if, for example, a MIR-instrumented counter is removed during an optimization. @@ -288,8 +178,8 @@ fn counter_regions(&'a self) -> impl Iterator { } fn expressions_with_regions( - &'a self, - ) -> (Vec, impl Iterator) { + &'tcx self, + ) -> (Vec, impl Iterator)>) { let mut counter_expressions = Vec::with_capacity(self.expressions.len()); let mut expression_regions = Vec::with_capacity(self.expressions.len()); let mut new_indexes = @@ -350,7 +240,7 @@ fn expressions_with_regions( (counter_expressions, expression_regions.into_iter()) } - fn unreachable_regions(&'a self) -> impl Iterator { + fn unreachable_regions(&'tcx self) -> impl Iterator)> { self.unreachable_regions.iter().map(|region| (Counter::zero(), region)) } diff --git a/src/librustc_codegen_ssa/coverageinfo/mod.rs b/src/librustc_codegen_ssa/coverageinfo/mod.rs index 1f0ffd289b1..ff794a75c36 100644 --- a/src/librustc_codegen_ssa/coverageinfo/mod.rs +++ b/src/librustc_codegen_ssa/coverageinfo/mod.rs @@ -2,3 +2,4 @@ pub mod map; pub use map::ExprKind; +pub use map::Region; diff --git a/src/librustc_codegen_ssa/mir/place.rs b/src/librustc_codegen_ssa/mir/place.rs index 0c8638b673d..05656774f0e 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/src/librustc_codegen_ssa/mir/place.rs @@ -253,14 +253,13 @@ pub fn codegen_get_discr>( 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) }; diff --git a/src/librustc_codegen_ssa/traits/coverageinfo.rs b/src/librustc_codegen_ssa/traits/coverageinfo.rs index db1d86c974e..2b5878f46bc 100644 --- a/src/librustc_codegen_ssa/traits/coverageinfo.rs +++ b/src/librustc_codegen_ssa/traits/coverageinfo.rs @@ -1,5 +1,5 @@ use super::BackendTypes; -use crate::coverageinfo::ExprKind; +use crate::coverageinfo::{ExprKind, Region}; use rustc_middle::ty::Instance; pub trait CoverageInfoMethods: BackendTypes { @@ -12,8 +12,7 @@ fn add_counter_region( instance: Instance<'tcx>, function_source_hash: u64, index: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ); fn add_counter_expression_region( @@ -23,14 +22,8 @@ fn add_counter_expression_region( lhs: u32, op: ExprKind, rhs: u32, - start_byte_pos: u32, - end_byte_pos: u32, + region: Region<'tcx>, ); - fn add_unreachable_region( - &mut self, - instance: Instance<'tcx>, - start_byte_pos: u32, - end_byte_pos: u32, - ); + fn add_unreachable_region(&mut self, instance: Instance<'tcx>, region: Region<'tcx>); } diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 7af640c109e..cc954cee907 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -677,7 +677,7 @@ fn print_crate_info( 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; diff --git a/src/librustc_error_codes/error_codes/E0271.md b/src/librustc_error_codes/error_codes/E0271.md index 31334069ed8..ddd245b1a2b 100644 --- a/src/librustc_error_codes/error_codes/E0271.md +++ b/src/librustc_error_codes/error_codes/E0271.md @@ -5,25 +5,6 @@ Erroneous code example: ```compile_fail,E0271 trait Trait { type AssociatedType; } -fn foo(t: T) where T: Trait { - 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) where T: Trait { // ~~~~~~~~ ~~~~~~~~~~~~~~~~~~ // | | @@ -56,11 +37,9 @@ foo(3_i8); // 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) where T: Trait { @@ -70,13 +49,17 @@ fn foo(t: T) where T: Trait { 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) where T: Trait { + println!("in foo"); } + +impl Trait for i8 { type AssociatedType = u32; } + +foo(3_i8); ``` diff --git a/src/librustc_error_codes/error_codes/E0502.md b/src/librustc_error_codes/error_codes/E0502.md index b90c59f5807..dc3ffdfddd9 100644 --- a/src/librustc_error_codes/error_codes/E0502.md +++ b/src/librustc_error_codes/error_codes/E0502.md @@ -5,7 +5,7 @@ Erroneous code example: ```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); @@ -19,7 +19,7 @@ variable before trying to access it mutably: fn bar(x: &mut i32) {} fn foo(a: &mut i32) { bar(a); - let ref y = a; // ok! + let y = &a; // ok! println!("{}", y); } ``` diff --git a/src/librustc_error_codes/error_codes/E0745.md b/src/librustc_error_codes/error_codes/E0745.md index 6595691ce78..23ee7af30f4 100644 --- a/src/librustc_error_codes/error_codes/E0745.md +++ b/src/librustc_error_codes/error_codes/E0745.md @@ -1,20 +1,23 @@ -Cannot take address of temporary value. +The address of temporary value was taken. Erroneous code example: ```compile_fail,E0745 # #![feature(raw_ref_op)] fn temp_address() { - let ptr = &raw const 2; // ERROR + let ptr = &raw const 2; // error! } ``` -To avoid the error, first bind the temporary to a named local variable. +In this example, `2` is destroyed right after the assignment, which means that +`ptr` now points to an unavailable location. + +To avoid this error, first bind the temporary to a named local variable: ``` # #![feature(raw_ref_op)] fn temp_address() { let val = 2; - let ptr = &raw const val; + let ptr = &raw const val; // ok! } ``` diff --git a/src/librustc_error_codes/error_codes/E0746.md b/src/librustc_error_codes/error_codes/E0746.md index 305667e58f8..90755d47f67 100644 --- a/src/librustc_error_codes/error_codes/E0746.md +++ b/src/librustc_error_codes/error_codes/E0746.md @@ -1,4 +1,4 @@ -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: @@ -13,11 +13,13 @@ impl T for S { // 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`]: @@ -32,7 +34,7 @@ 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) } ``` @@ -57,7 +59,7 @@ impl T for O { // This now returns a "trait object" and callers are only be able to access // associated items from `T`. -fn foo(x: bool) -> Box { +fn foo(x: bool) -> Box { // ok! if x { Box::new(S(42)) } else { diff --git a/src/librustc_error_codes/error_codes/E0747.md b/src/librustc_error_codes/error_codes/E0747.md index df1afbfef46..caf7e0fba07 100644 --- a/src/librustc_error_codes/error_codes/E0747.md +++ b/src/librustc_error_codes/error_codes/E0747.md @@ -1,4 +1,4 @@ -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: @@ -11,7 +11,7 @@ type X = S<(), 'static>; // error: the type argument is provided before the ``` 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); diff --git a/src/librustc_error_codes/error_codes/E0750.md b/src/librustc_error_codes/error_codes/E0750.md index e0cf56f716f..905e852f8d5 100644 --- a/src/librustc_error_codes/error_codes/E0750.md +++ b/src/librustc_error_codes/error_codes/E0750.md @@ -1,4 +1,18 @@ -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. diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index 1362a1155bc..cca8b47c781 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -362,7 +362,7 @@ fn render_multispan_macro_backtrace(&self, span: &mut MultiSpan, always_backtrac format!( "in this expansion of `{}`{}", trace.kind.descr(), - if macro_backtrace.len() > 2 { + if macro_backtrace.len() > 1 { // if macro_backtrace.len() == 1 it'll be // pointed at by "in this macro invocation" format!(" (#{})", i + 1) @@ -393,7 +393,7 @@ fn render_multispan_macro_backtrace(&self, span: &mut MultiSpan, always_backtrac trace.call_site, format!( "in this macro invocation{}", - if macro_backtrace.len() > 2 && always_backtrace { + if macro_backtrace.len() > 1 && always_backtrace { // only specify order when the macro // backtrace is multiple levels deep format!(" (#{})", i + 1) diff --git a/src/librustc_expand/base.rs b/src/librustc_expand/base.rs index daa75d42324..5a36df8299c 100644 --- a/src/librustc_expand/base.rs +++ b/src/librustc_expand/base.rs @@ -12,7 +12,7 @@ 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}; @@ -790,7 +790,7 @@ pub fn default(kind: SyntaxExtensionKind, edition: Edition) -> SyntaxExtension { /// 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, @@ -798,27 +798,29 @@ pub fn new( 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::>().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), @@ -941,7 +943,7 @@ pub struct ExpansionData { /// 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, pub root_path: PathBuf, @@ -954,13 +956,13 @@ pub struct ExtCtxt<'a> { 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, @@ -988,13 +990,13 @@ pub fn monotonic_expander<'b>(&'b mut self) -> expand::MacroExpander<'b, 'a> { 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 @@ -1026,7 +1028,7 @@ pub fn expansion_cause(&self) -> Option { } pub fn struct_span_err>(&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 @@ -1035,17 +1037,17 @@ pub fn struct_span_err>(&self, sp: S, msg: &str) -> Diagnosti /// Compilation will be stopped in the near future (at the end of /// the macro expansion phase). pub fn span_err>(&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>(&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>(&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); } @@ -1055,7 +1057,7 @@ pub fn trace_macros_diag(&mut self) { 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 diff --git a/src/librustc_expand/config.rs b/src/librustc_expand/config.rs index d79dabb5092..f6ddcd35068 100644 --- a/src/librustc_expand/config.rs +++ b/src/librustc_expand/config.rs @@ -13,7 +13,8 @@ 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}; @@ -22,15 +23,14 @@ /// 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>, ) -> 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"); @@ -53,6 +53,7 @@ fn active_features_up_to(edition: Edition) -> impl Iterator impl Iterator impl Iterator impl Iterator impl Iterator>, -) -> (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 => { @@ -213,7 +209,7 @@ pub fn features( } 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); @@ -281,9 +277,9 @@ fn process_cfg_attr(&mut self, attr: Attribute) -> Vec { } // 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![]; } @@ -303,8 +299,10 @@ fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, S 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)) @@ -320,6 +318,7 @@ fn parse_cfg_attr(&self, attr: &Attribute) -> Option<(MetaItem, Vec<(AttrItem, S 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( @@ -335,10 +334,10 @@ fn error_malformed_cfg_attr_missing(&self, span: Span) { /// 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(); @@ -346,7 +345,7 @@ pub fn in_cfg(&self, attrs: &[Attribute]) -> bool { } }; 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, @@ -364,7 +363,9 @@ pub fn in_cfg(&self, attrs: &[Attribute]) -> bool { 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", ""), }, } @@ -383,7 +384,7 @@ fn visit_expr_attrs(&mut self, attrs: &[Attribute]) { 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", @@ -452,9 +453,9 @@ pub fn configure_expr(&mut self, expr: &mut P) { // // 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) @@ -527,6 +528,6 @@ fn visit_fn_decl(&mut self, mut fn_decl: &mut P) { } } -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) } diff --git a/src/librustc_expand/expand.rs b/src/librustc_expand/expand.rs index 0cc340c205a..8da56dc67e5 100644 --- a/src/librustc_expand/expand.rs +++ b/src/librustc_expand/expand.rs @@ -527,7 +527,7 @@ pub fn fully_expand_fragment(&mut self, input_fragment: AstFragment) -> AstFragm } 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 @@ -566,10 +566,7 @@ fn collect_invocations( 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, @@ -589,8 +586,7 @@ fn collect_invocations( } 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 { @@ -706,7 +702,7 @@ fn expand_invoc( 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"); @@ -719,7 +715,7 @@ fn expand_invoc( 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, @@ -748,9 +744,9 @@ fn expand_invoc( } } 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)) @@ -808,7 +804,7 @@ fn gate_proc_macro_attr_item(&self, span: Span, item: &Annotatable) { 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), @@ -843,7 +839,8 @@ fn visit_mac(&mut self, _: &'ast ast::MacCall) {} } 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 }); } } @@ -989,7 +986,7 @@ fn collect(&mut self, fragment_kind: AstFragmentKind, kind: InvocationKind) -> A ..ExpnData::default( ExpnKind::Macro(MacroKind::Attr, sym::derive), item.span(), - self.cx.parse_sess.edition, + self.cx.sess.parse_sess.edition, None, ) }), @@ -1049,7 +1046,7 @@ fn find_attr_invoc( 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 { @@ -1058,7 +1055,7 @@ fn find_attr_invoc( && !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", @@ -1109,8 +1106,8 @@ fn configure(&mut self, node: T) -> Option { 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) { @@ -1123,7 +1120,7 @@ fn check_attributes(&mut self, attrs: &[ast::Attribute]) { } 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, @@ -1429,7 +1426,7 @@ fn visit_block(&mut self, block: &mut P) { }) } 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(); @@ -1438,11 +1435,11 @@ fn visit_block(&mut self, block: &mut P) { 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, @@ -1639,7 +1636,7 @@ fn flat_map_generic_param( 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); } @@ -1660,9 +1657,9 @@ fn visit_attribute(&mut self, at: &mut ast::Attribute) { } 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); } diff --git a/src/librustc_expand/mbe/macro_rules.rs b/src/librustc_expand/mbe/macro_rules.rs index 74d4023b410..15b2c14a257 100644 --- a/src/librustc_expand/mbe/macro_rules.rs +++ b/src/librustc_expand/mbe/macro_rules.rs @@ -19,6 +19,7 @@ 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}; @@ -217,7 +218,7 @@ fn generic_extension<'cx>( lhses: &[mbe::TokenTree], rhses: &[mbe::TokenTree], ) -> Box { - 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)); @@ -378,7 +379,7 @@ fn generic_extension<'cx>( /// Converts a macro item into a syntax extension. pub fn compile_declarative_macro( - sess: &ParseSess, + sess: &Session, features: &Features, def: &ast::Item, edition: Edition, @@ -396,7 +397,7 @@ pub fn compile_declarative_macro( ) }; - 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); @@ -444,17 +445,20 @@ pub fn compile_declarative_macro( ), ]; - 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 => { @@ -471,17 +475,18 @@ pub fn compile_declarative_macro( .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::>(), - _ => 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)] { @@ -490,29 +495,34 @@ pub fn compile_declarative_macro( .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::>(), - _ => 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)) diff --git a/src/librustc_expand/module.rs b/src/librustc_expand/module.rs index 535c1dbad04..12fe49ed585 100644 --- a/src/librustc_expand/module.rs +++ b/src/librustc_expand/module.rs @@ -1,8 +1,9 @@ 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}; @@ -39,7 +40,7 @@ pub struct ModulePathSuccess { } crate fn parse_external_mod( - sess: &ParseSess, + sess: &Session, id: Ident, span: Span, // The span to blame on errors. Directory { mut ownership, path }: Directory, @@ -53,14 +54,15 @@ pub struct ModulePathSuccess { 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 }; @@ -98,11 +100,12 @@ fn error_on_circular_module<'a>( } 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 { @@ -124,14 +127,14 @@ fn error_on_circular_module<'a>( } 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 @@ -151,16 +154,16 @@ fn submod_path<'a>( 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) } } } @@ -218,9 +221,13 @@ fn error_cannot_declare_mod_here<'a, T>( /// 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 { +pub fn submod_path_from_attr( + sess: &Session, + attrs: &[Attribute], + dir_path: &Path, +) -> Option { // 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 diff --git a/src/librustc_expand/mut_visit/tests.rs b/src/librustc_expand/mut_visit/tests.rs index c22d2a100c3..0608ccfffb8 100644 --- a/src/librustc_expand/mut_visit/tests.rs +++ b/src/librustc_expand/mut_visit/tests.rs @@ -2,9 +2,9 @@ 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) { diff --git a/src/librustc_expand/parse/lexer/tests.rs b/src/librustc_expand/parse/lexer/tests.rs index b3775c78e73..87184444283 100644 --- a/src/librustc_expand/parse/lexer/tests.rs +++ b/src/librustc_expand/parse/lexer/tests.rs @@ -1,12 +1,12 @@ -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; @@ -223,13 +223,6 @@ macro_rules! test { }) } -#[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(|| { @@ -251,6 +244,9 @@ fn crlf_comments() { 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")) + ); }) } diff --git a/src/librustc_expand/parse/tests.rs b/src/librustc_expand/parse/tests.rs index fc9b9f2dab0..5c9116b2f13 100644 --- a/src/librustc_expand/parse/tests.rs +++ b/src/librustc_expand/parse/tests.rs @@ -5,13 +5,13 @@ 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; @@ -244,20 +244,20 @@ fn crlf_doc_comments() { 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::>(); - 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 "); }); } diff --git a/src/librustc_expand/proc_macro.rs b/src/librustc_expand/proc_macro.rs index 54012d62a72..85fbf3bc0d0 100644 --- a/src/librustc_expand/proc_macro.rs +++ b/src/librustc_expand/proc_macro.rs @@ -107,7 +107,7 @@ fn expand( 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); @@ -123,9 +123,9 @@ fn expand( } }; - 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 { @@ -140,7 +140,7 @@ fn expand( } // 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(); } diff --git a/src/librustc_expand/proc_macro_server.rs b/src/librustc_expand/proc_macro_server.rs index 881d7b84b70..dc7ba2d0424 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/src/librustc_expand/proc_macro_server.rs @@ -3,7 +3,6 @@ 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; @@ -148,11 +147,9 @@ macro_rules! op { 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![ @@ -169,7 +166,7 @@ macro_rules! op { 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)) @@ -367,7 +364,7 @@ impl<'a> Rustc<'a> { 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), diff --git a/src/librustc_expand/tests.rs b/src/librustc_expand/tests.rs index 283ea0f68d9..b562a690f83 100644 --- a/src/librustc_expand/tests.rs +++ b/src/librustc_expand/tests.rs @@ -1,9 +1,9 @@ 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; diff --git a/src/librustc_expand/tokenstream/tests.rs b/src/librustc_expand/tokenstream/tests.rs index bc171bec6ff..4e818e9feb0 100644 --- a/src/librustc_expand/tokenstream/tests.rs +++ b/src/librustc_expand/tokenstream/tests.rs @@ -2,7 +2,7 @@ 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; diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index d7c310a8b4c..31aba8aba25 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -576,9 +576,12 @@ pub fn set(&self, features: &mut Features, span: Span) { /// 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 // ------------------------------------------------------------------------- diff --git a/src/librustc_hir/def.rs b/src/librustc_hir/def.rs index af1860ca6bf..618f3e99c3f 100644 --- a/src/librustc_hir/def.rs +++ b/src/librustc_hir/def.rs @@ -150,7 +150,7 @@ pub fn article(&self) -> &'static str { } } - pub fn matches_ns(&self, ns: Namespace) -> bool { + pub fn ns(&self) -> Option { match self { DefKind::Mod | DefKind::Struct @@ -163,7 +163,7 @@ pub fn matches_ns(&self, ns: Namespace) -> bool { | DefKind::ForeignTy | DefKind::TraitAlias | DefKind::AssocTy - | DefKind::TyParam => ns == Namespace::TypeNS, + | DefKind::TyParam => Some(Namespace::TypeNS), DefKind::Fn | DefKind::Const @@ -171,9 +171,9 @@ pub fn matches_ns(&self, ns: Namespace) -> bool { | 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 @@ -185,7 +185,7 @@ pub fn matches_ns(&self, ns: Namespace) -> bool { | DefKind::Use | DefKind::ForeignMod | DefKind::GlobalAsm - | DefKind::Impl => false, + | DefKind::Impl => None, } } } @@ -453,7 +453,7 @@ pub fn macro_kind(self) -> Option { 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, diff --git a/src/librustc_hir/lang_items.rs b/src/librustc_hir/lang_items.rs index 4b71407acfb..7f473a45848 100644 --- a/src/librustc_hir/lang_items.rs +++ b/src/librustc_hir/lang_items.rs @@ -141,12 +141,20 @@ fn hash_stable(&self, _: &mut CTX, hasher: &mut StableHasher) { /// 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, }) }) diff --git a/src/librustc_hir/weak_lang_items.rs b/src/librustc_hir/weak_lang_items.rs index c0560eb8d45..fd64361cb35 100644 --- a/src/librustc_hir/weak_lang_items.rs +++ b/src/librustc_hir/weak_lang_items.rs @@ -20,8 +20,13 @@ macro_rules! weak_lang_items { }; } -pub fn link_name(attrs: &[ast::Attribute]) -> Option { - 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 +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)* { diff --git a/src/librustc_incremental/assert_dep_graph.rs b/src/librustc_incremental/assert_dep_graph.rs index b1665d9e1ae..df602d8bd1b 100644 --- a/src/librustc_incremental/assert_dep_graph.rs +++ b/src/librustc_incremental/assert_dep_graph.rs @@ -117,7 +117,7 @@ fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) { 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), @@ -132,7 +132,7 @@ fn process_attrs(&mut self, hir_id: hir::HirId, attrs: &[ast::Attribute]) { }, }; 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) { diff --git a/src/librustc_incremental/assert_module_sources.rs b/src/librustc_incremental/assert_module_sources.rs index d451d9a22a4..ed04a947485 100644 --- a/src/librustc_incremental/assert_module_sources.rs +++ b/src/librustc_incremental/assert_module_sources.rs @@ -39,8 +39,8 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { .collect_and_partition_mono_items(LOCAL_CRATE) .1 .iter() - .map(|cgu| cgu.name()) - .collect::>(); + .map(|cgu| cgu.name().to_string()) + .collect::>(); let ams = AssertModuleSource { tcx, available_cgus }; @@ -52,31 +52,32 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { struct AssertModuleSource<'tcx> { tcx: TyCtxt<'tcx>, - available_cgus: BTreeSet, + available_cgus: BTreeSet, } 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( @@ -121,12 +122,11 @@ fn check_attr(&self, attr: &ast::Attribute) { 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 diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/src/librustc_incremental/persist/dirty_clean.rs index 02f37f82352..0f254aee8e3 100644 --- a/src/librustc_incremental/persist/dirty_clean.rs +++ b/src/librustc_incremental/persist/dirty_clean.rs @@ -180,9 +180,9 @@ pub struct DirtyCleanVisitor<'tcx> { impl DirtyCleanVisitor<'tcx> { /// Possibly "deserialize" the attribute into a clean/dirty assertion fn assertion_maybe(&mut self, item_id: hir::HirId, attr: &Attribute) -> Option { - 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 @@ -523,7 +523,7 @@ pub struct FindAllAttrs<'tcx> { 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; } } diff --git a/src/librustc_index/bit_set.rs b/src/librustc_index/bit_set.rs index b369be25218..e4b7c24a249 100644 --- a/src/librustc_index/bit_set.rs +++ b/src/librustc_index/bit_set.rs @@ -1034,6 +1034,30 @@ pub trait FiniteBitSetTy: fn checked_shr(self, rhs: u32) -> Option; } +impl FiniteBitSetTy for u32 { + const DOMAIN_SIZE: u32 = 32; + + const FILLED: Self = Self::MAX; + const EMPTY: Self = Self::MIN; + + const ONE: Self = 1u32; + const ZERO: Self = 0u32; + + fn checked_shl(self, rhs: u32) -> Option { + self.checked_shl(rhs) + } + + fn checked_shr(self, rhs: u32) -> Option { + self.checked_shr(rhs) + } +} + +impl std::fmt::Debug for FiniteBitSet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:032b}", self.0) + } +} + impl FiniteBitSetTy for u64 { const DOMAIN_SIZE: u32 = 64; diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 72deba990b0..89142edb2dc 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -85,11 +85,7 @@ pub(super) fn try_report_named_anon_conflict(&self) -> Option Option { param.param_ty.to_string(), Applicability::MaybeIncorrect, ); - } else if let Some(_) = opaque + } else if opaque .bounds .iter() .filter_map(|arg| match arg { @@ -269,6 +269,7 @@ pub(super) fn try_report_static_impl_trait(&self) -> Option { _ => None, }) .next() + .is_some() { } else { err.span_suggestion_verbose( diff --git a/src/librustc_infer/infer/glb.rs b/src/librustc_infer/infer/glb.rs index 8a0ab52f383..ccba904df9e 100644 --- a/src/librustc_infer/infer/glb.rs +++ b/src/librustc_infer/infer/glb.rs @@ -50,7 +50,7 @@ fn relate_with_variance>( 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), } } @@ -97,7 +97,7 @@ fn binders( // 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) } } diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/src/librustc_infer/infer/nll_relate/mod.rs index cb1f1c08d88..3f5ed36035c 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/src/librustc_infer/infer/nll_relate/mod.rs @@ -719,7 +719,7 @@ fn binders( self.a_scopes.pop().unwrap(); } - Ok(a.clone()) + Ok(a) } } diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/src/librustc_infer/infer/region_constraints/leak_check.rs index 32e708bf52b..2d4c1e5d050 100644 --- a/src/librustc_infer/infer/region_constraints/leak_check.rs +++ b/src/librustc_infer/infer/region_constraints/leak_check.rs @@ -288,9 +288,9 @@ fn error( ) -> 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) } } } diff --git a/src/librustc_infer/infer/sub.rs b/src/librustc_infer/infer/sub.rs index 4f860c77d65..308f884f9a6 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/src/librustc_infer/infer/sub.rs @@ -68,7 +68,7 @@ fn relate_with_variance>( 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)), } } diff --git a/src/librustc_interface/interface.rs b/src/librustc_interface/interface.rs index e50622a0053..4dccf273dd9 100644 --- a/src/librustc_interface/interface.rs +++ b/src/librustc_interface/interface.rs @@ -17,7 +17,6 @@ use rustc_session::lint; use rustc_session::parse::{CrateConfig, ParseSess}; use rustc_session::{DiagnosticOutput, Session}; -use rustc_span::edition; use rustc_span::source_map::{FileLoader, FileName}; use std::path::PathBuf; use std::result; @@ -74,7 +73,7 @@ pub fn build_output_filenames( /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. pub fn parse_cfgspecs(cfgspecs: Vec) -> FxHashSet<(String, Option)> { - rustc_ast::with_default_session_globals(move || { + rustc_span::with_default_session_globals(move || { let cfg = cfgspecs .into_iter() .map(|s| { @@ -208,13 +207,3 @@ pub fn run_compiler(mut config: Config, f: impl FnOnce(&Compiler) -> R || create_compiler_and_run(config, f), ) } - -pub fn setup_callbacks_and_run_in_default_thread_pool_with_globals( - edition: edition::Edition, - f: impl FnOnce() -> R + Send, -) -> R { - // the 1 here is duplicating code in config.opts.debugging_opts.threads - // which also defaults to 1; it ultimately doesn't matter as the default - // isn't threaded, and just ignores this parameter - util::setup_callbacks_and_run_in_thread_pool_with_globals(edition, 1, &None, f) -} diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index 3a562847d3e..6c0343330c8 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -162,12 +162,7 @@ pub fn register_plugins<'a>( ) }); - 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); @@ -244,7 +239,7 @@ fn configure_and_expand_inner<'a>( 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 { @@ -253,7 +248,7 @@ fn configure_and_expand_inner<'a>( 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", || { @@ -300,7 +295,7 @@ fn configure_and_expand_inner<'a>( }; 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)); @@ -312,6 +307,7 @@ fn configure_and_expand_inner<'a>( }); let mut missing_fragment_specifiers: Vec<_> = ecx + .sess .parse_sess .missing_fragment_specifiers .borrow() @@ -341,17 +337,7 @@ fn configure_and_expand_inner<'a>( })?; 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 { @@ -385,7 +371,7 @@ fn configure_and_expand_inner<'a>( 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, @@ -415,12 +401,7 @@ fn configure_and_expand_inner<'a>( // 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`. diff --git a/src/librustc_interface/proc_macro_decls.rs b/src/librustc_interface/proc_macro_decls.rs index e91003b450c..d56115fd6ac 100644 --- a/src/librustc_interface/proc_macro_decls.rs +++ b/src/librustc_interface/proc_macro_decls.rs @@ -1,4 +1,3 @@ -use rustc_ast::attr; use rustc_hir as hir; use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; @@ -13,19 +12,20 @@ pub fn find(tcx: TyCtxt<'_>) -> Option { fn proc_macro_decls_static(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option { 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, } -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); } } diff --git a/src/librustc_interface/queries.rs b/src/librustc_interface/queries.rs index 4265e6dca6a..d1a22c69ee0 100644 --- a/src/librustc_interface/queries.rs +++ b/src/librustc_interface/queries.rs @@ -159,7 +159,7 @@ pub fn crate_name(&self) -> Result<&Query> { 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) } }) }) @@ -294,7 +294,7 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) { }; 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)]`. diff --git a/src/librustc_interface/tests.rs b/src/librustc_interface/tests.rs index 22197a66530..e94745519a4 100644 --- a/src/librustc_interface/tests.rs +++ b/src/librustc_interface/tests.rs @@ -73,7 +73,7 @@ fn mk_map(entries: Vec<(K, V)>) -> BTreeMap { // 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)); @@ -84,7 +84,7 @@ fn test_switch_implies_cfg_test() { // 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)); @@ -96,20 +96,20 @@ fn test_switch_implies_cfg_test_unless_cfg_test() { #[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()); diff --git a/src/librustc_interface/util.rs b/src/librustc_interface/util.rs index bbb2f9d8b25..e403a60ff32 100644 --- a/src/librustc_interface/util.rs +++ b/src/librustc_interface/util.rs @@ -142,7 +142,7 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals R + Se 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()))); } @@ -176,27 +176,21 @@ pub fn setup_callbacks_and_run_in_thread_pool_with_globals R + Se 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() }) }) } @@ -407,10 +401,14 @@ pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguat CrateDisambiguator::from(hasher.finish::()) } -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; @@ -465,7 +463,7 @@ pub fn collect_crate_types(session: &Session, attrs: &[ast::Attribute]) -> Vec = 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, @@ -531,7 +529,7 @@ pub fn build_output_filenames( .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( diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs index 6515708e115..c42794e00b4 100644 --- a/src/librustc_lint/builtin.rs +++ b/src/librustc_lint/builtin.rs @@ -41,6 +41,7 @@ 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}; @@ -237,7 +238,7 @@ fn report_unsafe( 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 \ @@ -315,12 +316,12 @@ pub struct MissingDoc { 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; } @@ -377,7 +378,7 @@ fn check_missing_docs_attrs( } } - 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, @@ -391,10 +392,10 @@ fn check_missing_docs_attrs( } 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), @@ -411,7 +412,7 @@ fn check_crate(&mut self, cx: &LateContext<'_>, krate: &hir::Crate<'_>) { 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, @@ -737,7 +738,7 @@ fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &ast::Attribute) { 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); @@ -763,7 +764,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & 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( @@ -819,7 +820,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { 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 { .. } => {} @@ -845,7 +846,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { } } 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| { @@ -938,11 +939,11 @@ fn def_id_is_transmute(cx: &LateContext<'_>, def_id: DefId) -> bool { ); 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() }); } @@ -1381,7 +1382,7 @@ fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { 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() }); @@ -2131,7 +2132,7 @@ fn name_of_extern_decl(tcx: TyCtxt<'_>, fi: &hir::ForeignItem<'_>) -> SymbolName 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, ) diff --git a/src/librustc_lint/levels.rs b/src/librustc_lint/levels.rs index 2e9cd962a74..145a07d8dc8 100644 --- a/src/librustc_lint/levels.rs +++ b/src/librustc_lint/levels.rs @@ -125,7 +125,7 @@ pub fn push( }; 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); diff --git a/src/librustc_lint/nonstandard_style.rs b/src/librustc_lint/nonstandard_style.rs index dc6b8670498..5ca6f461048 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/src/librustc_lint/nonstandard_style.rs @@ -127,7 +127,7 @@ fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { 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; @@ -263,7 +263,8 @@ fn check_mod( 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| { @@ -327,7 +328,7 @@ fn check_fn( }, 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); @@ -407,7 +408,7 @@ fn check_upper_case(cx: &LateContext<'_>, sort: &str, ident: &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(..) => { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index de750010ed1..5c53e435fd7 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -538,7 +538,7 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi 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; @@ -556,6 +556,7 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi _ => 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> { @@ -1074,7 +1075,7 @@ fn check_type_for_ffi_and_report_errors( } // 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()); } diff --git a/src/librustc_lint/unused.rs b/src/librustc_lint/unused.rs index 1e98ddbd7db..5de9a16e098 100644 --- a/src/librustc_lint/unused.rs +++ b/src/librustc_lint/unused.rs @@ -2,7 +2,6 @@ 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; @@ -242,7 +241,7 @@ fn check_must_use_def( 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", @@ -331,7 +330,7 @@ fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { } } - 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() diff --git a/src/librustc_metadata/creader.rs b/src/librustc_metadata/creader.rs index 9bc6c054e4d..e15655e3794 100644 --- a/src/librustc_metadata/creader.rs +++ b/src/librustc_metadata/creader.rs @@ -4,8 +4,8 @@ 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; @@ -636,7 +636,8 @@ fn inject_panic_runtime(&mut self, krate: &ast::Crate) { // 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(); @@ -716,7 +717,7 @@ fn inject_profiler_runtime(&mut self) { } 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") @@ -731,7 +732,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) { // 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(); }); @@ -785,7 +786,7 @@ fn inject_allocator_crate(&mut self, krate: &ast::Crate) { // 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; @@ -895,12 +896,12 @@ pub fn process_extern_crate( ); 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 @@ -945,3 +946,26 @@ pub fn maybe_process_path_extern(&mut self, name: Symbol) -> Option { self.maybe_resolve_crate(name, CrateDepKind::Explicit, None).ok() } } + +fn global_allocator_spans(sess: &Session, krate: &ast::Crate) -> Vec { + struct Finder<'a> { + sess: &'a Session, + name: Symbol, + spans: Vec, + } + 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 +} diff --git a/src/librustc_metadata/link_args.rs b/src/librustc_metadata/link_args.rs index c5a43b91b5e..d8f16796083 100644 --- a/src/librustc_metadata/link_args.rs +++ b/src/librustc_metadata/link_args.rs @@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi; crate fn collect(tcx: TyCtxt<'_>) -> Vec { - 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() { @@ -19,11 +19,12 @@ collector.args } -struct Collector { +struct Collector<'tcx> { + tcx: TyCtxt<'tcx>, args: Vec, } -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, @@ -34,7 +35,8 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { } // 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); } @@ -45,7 +47,7 @@ fn visit_trait_item(&mut self, _it: &'tcx hir::TraitItem<'tcx>) {} 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())) } diff --git a/src/librustc_metadata/native_libs.rs b/src/librustc_metadata/native_libs.rs index d01c598d059..3976475cb06 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/src/librustc_metadata/native_libs.rs @@ -43,7 +43,8 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { } // 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, @@ -71,16 +72,10 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { "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 } }; @@ -92,18 +87,18 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { 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 { @@ -117,7 +112,7 @@ fn visit_item(&mut self, it: &'tcx hir::Item<'tcx>) { 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 \ diff --git a/src/librustc_metadata/rmeta/decoder.rs b/src/librustc_metadata/rmeta/decoder.rs index 3c045df45da..8aea9a9f588 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/src/librustc_metadata/rmeta/decoder.rs @@ -78,7 +78,8 @@ /// Trait impl data. /// FIXME: Used only from queries and can use query cache, /// so pre-decoding can probably be avoided. - trait_impls: FxHashMap<(u32, DefIndex), Lazy<[DefIndex]>>, + trait_impls: + FxHashMap<(u32, DefIndex), Lazy<[(DefIndex, Option)]>>, /// Proc macro descriptions for this crate, if it's a proc macro crate. raw_proc_macros: Option<&'static [ProcMacro]>, /// Source maps for code from the crate. @@ -741,7 +742,7 @@ fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension { }; SyntaxExtension::new( - &sess.parse_sess, + sess, kind, self.get_span(id, sess), helper_attrs, @@ -1101,7 +1102,7 @@ fn each_child_of_item(&self, id: DefIndex, mut callback: F, sess: &Session) // 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); } @@ -1150,7 +1151,7 @@ fn get_optimized_mir(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> { .decode((self, tcx)) } - fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { + fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { self.root .tables .unused_generic_params @@ -1289,7 +1290,7 @@ fn get_implementations_for_trait( &self, tcx: TyCtxt<'tcx>, filter: Option, - ) -> &'tcx [DefId] { + ) -> &'tcx [(DefId, Option)] { if self.root.is_proc_macro_crate() { // proc-macro crates export no trait impls. return &[]; @@ -1305,16 +1306,20 @@ fn get_implementations_for_trait( if let Some(filter) = filter { if let Some(impls) = self.trait_impls.get(&filter) { - tcx.arena.alloc_from_iter(impls.decode(self).map(|idx| self.local_def_id(idx))) + tcx.arena.alloc_from_iter( + impls.decode(self).map(|(idx, simplified_self_ty)| { + (self.local_def_id(idx), simplified_self_ty) + }), + ) } else { &[] } } else { - tcx.arena.alloc_from_iter( - self.trait_impls - .values() - .flat_map(|impls| impls.decode(self).map(|idx| self.local_def_id(idx))), - ) + tcx.arena.alloc_from_iter(self.trait_impls.values().flat_map(|impls| { + impls + .decode(self) + .map(|(idx, simplified_self_ty)| (self.local_def_id(idx), simplified_self_ty)) + })) } } diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs index e51862be9a8..10b89cdd15a 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/src/librustc_metadata/rmeta/decoder/cstore_impl.rs @@ -5,7 +5,6 @@ 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; @@ -37,7 +36,7 @@ pub fn provide_extern(providers: &mut Providers) { 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(); @@ -415,7 +414,7 @@ pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro { // 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); diff --git a/src/librustc_metadata/rmeta/encoder.rs b/src/librustc_metadata/rmeta/encoder.rs index 6872693a66c..f75f0b74a0e 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/src/librustc_metadata/rmeta/encoder.rs @@ -3,7 +3,6 @@ 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::stable_hasher::StableHasher; @@ -162,7 +161,7 @@ impl<'a, 'tcx> SpecializedEncoder for EncodeContext<'a, 'tcx> { 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, ) @@ -637,7 +636,7 @@ fn encode_crate_root(&mut self) -> Lazy> { 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), @@ -663,12 +662,12 @@ fn encode_crate_root(&mut self) -> Lazy> { } 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, @@ -1138,8 +1137,11 @@ fn encode_optimized_mir(&mut self, def_id: LocalDefId) { debug!("EntryBuilder::encode_mir({:?})", def_id); if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) { record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id)); - record!(self.tables.unused_generic_params[def_id.to_def_id()] <- - self.tcx.unused_generic_params(def_id)); + + let unused = self.tcx.unused_generic_params(def_id); + if !unused.is_empty() { + record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); + } } } @@ -1611,7 +1613,7 @@ fn encode_impls(&mut self) -> Lazy<[TraitImpls]> { .into_iter() .map(|(trait_def_id, mut impls)| { // Bring everything into deterministic order for hashing - impls.sort_by_cached_key(|&index| { + impls.sort_by_cached_key(|&(index, _)| { tcx.hir().definitions().def_path_hash(LocalDefId { local_def_index: index }) }); @@ -1853,7 +1855,7 @@ fn encode_addl_info_for_item(&mut self, item: &hir::Item<'_>) { struct ImplVisitor<'tcx> { tcx: TyCtxt<'tcx>, - impls: FxHashMap>, + impls: FxHashMap)>>, } impl<'tcx, 'v> ItemLikeVisitor<'v> for ImplVisitor<'tcx> { @@ -1861,7 +1863,13 @@ fn visit_item(&mut self, item: &hir::Item<'_>) { if let hir::ItemKind::Impl { .. } = item.kind { let impl_id = self.tcx.hir().local_def_id(item.hir_id); if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_id.to_def_id()) { - self.impls.entry(trait_ref.def_id).or_default().push(impl_id.local_def_index); + let simplified_self_ty = + ty::fast_reject::simplify_type(self.tcx, trait_ref.self_ty(), false); + + self.impls + .entry(trait_ref.def_id) + .or_default() + .push((impl_id.local_def_index, simplified_self_ty)); } } } diff --git a/src/librustc_metadata/rmeta/mod.rs b/src/librustc_metadata/rmeta/mod.rs index 12d2f50363c..1c287be9f6b 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/src/librustc_metadata/rmeta/mod.rs @@ -233,7 +233,7 @@ macro_rules! Lazy { #[derive(RustcEncodable, RustcDecodable)] crate struct TraitImpls { trait_id: (u32, DefIndex), - impls: Lazy<[DefIndex]>, + impls: Lazy<[(DefIndex, Option)]>, } /// Define `LazyTables` and `TableBuilders` at the same time. @@ -285,7 +285,7 @@ fn encode(&self, buf: &mut Encoder) -> LazyTables<'tcx> { super_predicates: Table)>, mir: Table)>, promoted_mir: Table>)>, - unused_generic_params: Table>>, + unused_generic_params: Table>>, } #[derive(Copy, Clone, RustcEncodable, RustcDecodable)] diff --git a/src/librustc_middle/middle/limits.rs b/src/librustc_middle/middle/limits.rs index 85198482bd3..e9820539484 100644 --- a/src/librustc_middle/middle/limits.rs +++ b/src/librustc_middle/middle/limits.rs @@ -27,7 +27,7 @@ fn update_limit( default: usize, ) { for attr in &krate.attrs { - if !attr.check_name(name) { + if !sess.check_name(attr, name) { continue; } diff --git a/src/librustc_middle/mir/coverage/mod.rs b/src/librustc_middle/mir/coverage/mod.rs index 82365ef6a73..6b1514da644 100644 --- a/src/librustc_middle/mir/coverage/mod.rs +++ b/src/librustc_middle/mir/coverage/mod.rs @@ -4,8 +4,11 @@ pub mod count_code_region_args { pub const FUNCTION_SOURCE_HASH: usize = 0; pub const COUNTER_ID: usize = 1; - pub const START_BYTE_POS: usize = 2; - pub const END_BYTE_POS: usize = 3; + pub const FILE_NAME: usize = 2; + pub const START_LINE: usize = 3; + pub const START_COL: usize = 4; + pub const END_LINE: usize = 5; + pub const END_COL: usize = 6; } /// Positional arguments to `libcore::coverage_counter_add()` and @@ -14,12 +17,18 @@ pub mod coverage_counter_expression_args { pub const EXPRESSION_ID: usize = 0; pub const LEFT_ID: usize = 1; pub const RIGHT_ID: usize = 2; - pub const START_BYTE_POS: usize = 3; - pub const END_BYTE_POS: usize = 4; + pub const FILE_NAME: usize = 3; + pub const START_LINE: usize = 4; + pub const START_COL: usize = 5; + pub const END_LINE: usize = 6; + pub const END_COL: usize = 7; } /// Positional arguments to `libcore::coverage_unreachable()` pub mod coverage_unreachable_args { - pub const START_BYTE_POS: usize = 0; - pub const END_BYTE_POS: usize = 1; + pub const FILE_NAME: usize = 0; + pub const START_LINE: usize = 1; + pub const START_COL: usize = 2; + pub const END_LINE: usize = 3; + pub const END_COL: usize = 4; } diff --git a/src/librustc_middle/mir/interpret/value.rs b/src/librustc_middle/mir/interpret/value.rs index 2c76f0b5ad0..b4e7a5b98e3 100644 --- a/src/librustc_middle/mir/interpret/value.rs +++ b/src/librustc_middle/mir/interpret/value.rs @@ -56,6 +56,15 @@ pub fn try_to_scalar(&self) -> Option { } } + pub fn try_to_str_slice(&self) -> Option<&'tcx str> { + if let ConstValue::Slice { data, start, end } = *self { + ::std::str::from_utf8(data.inspect_with_undef_and_ptr_outside_interpreter(start..end)) + .ok() + } else { + None + } + } + pub fn try_to_bits(&self, size: Size) -> Option { self.try_to_scalar()?.to_bits(size).ok() } diff --git a/src/librustc_middle/mir/mod.rs b/src/librustc_middle/mir/mod.rs index 31b8de500e0..3b0c480f6d4 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/src/librustc_middle/mir/mod.rs @@ -2,7 +2,7 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html -use crate::mir::interpret::{GlobalAlloc, Scalar}; +use crate::mir::interpret::{Allocation, ConstValue, GlobalAlloc, Scalar}; use crate::mir::visit::MirVisitable; use crate::ty::adjustment::PointerCast; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; @@ -1842,6 +1842,33 @@ pub fn scalar_from_const(operand: &Operand<'tcx>) -> Scalar { } } + /// Convenience helper to make a literal-like constant from a given `&str` slice. + /// Since this is used to synthesize MIR, assumes `user_ty` is None. + pub fn const_from_str(tcx: TyCtxt<'tcx>, val: &str, span: Span) -> Operand<'tcx> { + let tcx = tcx; + let allocation = Allocation::from_byte_aligned_bytes(val.as_bytes()); + let allocation = tcx.intern_const_alloc(allocation); + let const_val = ConstValue::Slice { data: allocation, start: 0, end: val.len() }; + let ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.types.str_); + Operand::Constant(box Constant { + span, + user_ty: None, + literal: ty::Const::from_value(tcx, const_val, ty), + }) + } + + /// Convenience helper to make a `ConstValue` from the given `Operand`, assuming that `Operand` + /// wraps a constant value (such as a `&str` slice). Panics if this is not the case. + pub fn value_from_const(operand: &Operand<'tcx>) -> ConstValue<'tcx> { + match operand { + Operand::Constant(constant) => match constant.literal.val.try_to_value() { + Some(const_value) => const_value, + _ => panic!("{:?}: ConstValue expected", constant.literal.val), + }, + _ => panic!("{:?}: Constant expected", operand), + } + } + pub fn to_copy(&self) -> Self { match *self { Operand::Copy(_) | Operand::Constant(_) => self.clone(), diff --git a/src/librustc_middle/query/mod.rs b/src/librustc_middle/query/mod.rs index 862c046358b..a8f6723a356 100644 --- a/src/librustc_middle/query/mod.rs +++ b/src/librustc_middle/query/mod.rs @@ -1125,11 +1125,11 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { TypeChecking { query implementations_of_trait(_: (CrateNum, DefId)) - -> &'tcx [DefId] { + -> &'tcx [(DefId, Option)] { desc { "looking up implementations of a trait in a crate" } } query all_trait_implementations(_: CrateNum) - -> &'tcx [DefId] { + -> &'tcx [(DefId, Option)] { desc { "looking up all (?) trait implementations" } } } @@ -1319,7 +1319,7 @@ fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String { query codegen_unit(_: Symbol) -> &'tcx CodegenUnit<'tcx> { desc { "codegen_unit" } } - query unused_generic_params(key: DefId) -> FiniteBitSet { + query unused_generic_params(key: DefId) -> FiniteBitSet { cache_on_disk_if { key.is_local() } desc { |tcx| "determining which generic parameters are unused by `{}`", diff --git a/src/librustc_middle/traits/query.rs b/src/librustc_middle/traits/query.rs index 69696ac9e93..4b7663e9ade 100644 --- a/src/librustc_middle/traits/query.rs +++ b/src/librustc_middle/traits/query.rs @@ -128,7 +128,7 @@ pub struct DropckOutlivesResult<'tcx> { 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, diff --git a/src/librustc_middle/ty/context.rs b/src/librustc_middle/ty/context.rs index 6cbf5db8373..d6bcfbf49cf 100644 --- a/src/librustc_middle/ty/context.rs +++ b/src/librustc_middle/ty/context.rs @@ -1040,7 +1040,7 @@ pub fn intern_layout(self, layout: Layout) -> &'tcx Layout { pub fn layout_scalar_valid_range(self, def_id: DefId) -> (Bound, Bound) { 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, }; @@ -1380,7 +1380,9 @@ pub fn borrowck_mode(self) -> BorrowckMode { /// 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] @@ -2736,11 +2738,11 @@ pub fn provide(providers: &mut ty::query::Providers) { }; 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); diff --git a/src/librustc_middle/ty/flags.rs b/src/librustc_middle/ty/flags.rs index 27f50c240db..81f7474962c 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/src/librustc_middle/ty/flags.rs @@ -85,6 +85,8 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) { } &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); @@ -107,6 +109,8 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) { } &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); @@ -192,6 +196,8 @@ fn add_kind(&mut self, kind: &ty::TyKind<'_>) { } &ty::FnDef(_, substs) => { + self.add_flags(TypeFlags::MAY_POLYMORPHIZE); + self.add_substs(substs); } diff --git a/src/librustc_middle/ty/fold.rs b/src/librustc_middle/ty/fold.rs index 492f8ce9ef1..87434f3f267 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/src/librustc_middle/ty/fold.rs @@ -150,6 +150,12 @@ fn still_further_specializable(&self) -> bool { 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); diff --git a/src/librustc_middle/ty/instance.rs b/src/librustc_middle/ty/instance.rs index 289a9db7327..cf876db26bc 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/src/librustc_middle/ty/instance.rs @@ -474,26 +474,7 @@ pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self { } 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 { @@ -502,6 +483,82 @@ pub fn polymorphize(self, tcx: TyCtxt<'tcx>) -> Self { } } +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, diff --git a/src/librustc_middle/ty/mod.rs b/src/librustc_middle/ty/mod.rs index bd45f866abc..0102225b9b5 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/src/librustc_middle/ty/mod.rs @@ -575,6 +575,10 @@ pub struct TypeFlags: u32 { /// 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; } } @@ -2261,7 +2265,7 @@ pub fn new(tcx: TyCtxt<'_>, did: DefId) -> ReprOptions { let mut max_align: Option = None; let mut min_pack: Option = 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) => { @@ -2378,7 +2382,7 @@ fn new( } 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() { @@ -3017,7 +3021,7 @@ pub fn get_attrs(self, did: DefId) -> Attributes<'tcx> { /// 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`. diff --git a/src/librustc_middle/ty/query/job.rs b/src/librustc_middle/ty/query/job.rs index 1811d945a1d..bd2e7747b7d 100644 --- a/src/librustc_middle/ty/query/job.rs +++ b/src/librustc_middle/ty/query/job.rs @@ -15,16 +15,12 @@ pub unsafe fn handle_deadlock() { rustc_data_structures::sync::assert_sync::>(); 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))) }) }); } diff --git a/src/librustc_middle/ty/subst.rs b/src/librustc_middle/ty/subst.rs index e9fd67a748c..866b529f35e 100644 --- a/src/librustc_middle/ty/subst.rs +++ b/src/librustc_middle/ty/subst.rs @@ -425,8 +425,7 @@ fn subst_spanned( substs: &[GenericArg<'tcx>], span: Option, ) -> T { - let mut folder = - SubstFolder { tcx, substs, span, root_ty: None, ty_stack_depth: 0, binders_passed: 0 }; + let mut folder = SubstFolder { tcx, substs, span, binders_passed: 0 }; (*self).fold_with(&mut folder) } } @@ -441,12 +440,6 @@ struct SubstFolder<'a, 'tcx> { /// The location for which the substitution is performed, if available. span: Option, - /// The root type that is being substituted, if available. - root_ty: Option>, - - /// Depth of type stack - ty_stack_depth: usize, - /// Number of region binders we have passed through while doing the substitution binders_passed: u32, } @@ -478,9 +471,8 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { let span = self.span.unwrap_or(DUMMY_SP); let msg = format!( "Region parameter out of range \ - when substituting in region {} (root type={:?}) \ - (index={})", - data.name, self.root_ty, data.index + when substituting in region {} (index={})", + data.name, data.index ); span_bug!(span, "{}", msg); } @@ -495,25 +487,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { return t; } - // track the root type we were asked to substitute - let depth = self.ty_stack_depth; - if depth == 0 { - self.root_ty = Some(t); - } - self.ty_stack_depth += 1; - - let t1 = match t.kind { + match t.kind { ty::Param(p) => self.ty_for_param(p, t), _ => t.super_fold_with(self), - }; - - assert_eq!(depth + 1, self.ty_stack_depth); - self.ty_stack_depth -= 1; - if depth == 0 { - self.root_ty = None; } - - t1 } fn fold_const(&mut self, c: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> { @@ -540,12 +517,11 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { span_bug!( span, "expected type for `{:?}` ({:?}/{}) but found {:?} \ - when substituting (root type={:?}) substs={:?}", + when substituting, substs={:?}", p, source_ty, p.index, kind, - self.root_ty, self.substs, ); } @@ -554,11 +530,10 @@ fn ty_for_param(&self, p: ty::ParamTy, source_ty: Ty<'tcx>) -> Ty<'tcx> { span_bug!( span, "type parameter `{:?}` ({:?}/{}) out of range \ - when substituting (root type={:?}) substs={:?}", + when substituting, substs={:?}", p, source_ty, p.index, - self.root_ty, self.substs, ); } diff --git a/src/librustc_middle/ty/trait_def.rs b/src/librustc_middle/ty/trait_def.rs index 8f125098ee6..f93cce3f4da 100644 --- a/src/librustc_middle/ty/trait_def.rs +++ b/src/librustc_middle/ty/trait_def.rs @@ -187,32 +187,38 @@ pub(super) fn all_local_trait_impls<'tcx>( pub(super) fn trait_impls_of_provider(tcx: TyCtxt<'_>, trait_id: DefId) -> TraitImpls { let mut impls = TraitImpls::default(); - { - let mut add_impl = |impl_def_id: DefId| { - let impl_self_ty = tcx.type_of(impl_def_id); - if impl_def_id.is_local() && impl_self_ty.references_error() { - return; - } - - if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, false) { - impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); - } else { - impls.blanket_impls.push(impl_def_id); - } - }; - - // Traits defined in the current crate can't have impls in upstream - // crates, so we don't bother querying the cstore. - if !trait_id.is_local() { - for &cnum in tcx.crates().iter() { - for &def_id in tcx.implementations_of_trait((cnum, trait_id)).iter() { - add_impl(def_id); + // Traits defined in the current crate can't have impls in upstream + // crates, so we don't bother querying the cstore. + if !trait_id.is_local() { + for &cnum in tcx.crates().iter() { + for &(impl_def_id, simplified_self_ty) in + tcx.implementations_of_trait((cnum, trait_id)).iter() + { + if let Some(simplified_self_ty) = simplified_self_ty { + impls + .non_blanket_impls + .entry(simplified_self_ty) + .or_default() + .push(impl_def_id); + } else { + impls.blanket_impls.push(impl_def_id); } } } + } + + for &hir_id in tcx.hir().trait_impls(trait_id) { + let impl_def_id = tcx.hir().local_def_id(hir_id).to_def_id(); + + let impl_self_ty = tcx.type_of(impl_def_id); + if impl_self_ty.references_error() { + continue; + } - for &hir_id in tcx.hir().trait_impls(trait_id) { - add_impl(tcx.hir().local_def_id(hir_id).to_def_id()); + if let Some(simplified_self_ty) = fast_reject::simplify_type(tcx, impl_self_ty, false) { + impls.non_blanket_impls.entry(simplified_self_ty).or_default().push(impl_def_id); + } else { + impls.blanket_impls.push(impl_def_id); } } diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/src/librustc_mir/borrow_check/diagnostics/mod.rs index d8f6abd92f6..ba74ffaa8d6 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/src/librustc_mir/borrow_check/diagnostics/mod.rs @@ -868,7 +868,7 @@ pub(super) fn move_spans( } } } - return normal_ret; + normal_ret } /// Finds the span of arguments of a closure (within `maybe_closure_span`) diff --git a/src/librustc_mir/dataflow/framework/engine.rs b/src/librustc_mir/dataflow/framework/engine.rs index 2113d40a594..89e2d7088f7 100644 --- a/src/librustc_mir/dataflow/framework/engine.rs +++ b/src/librustc_mir/dataflow/framework/engine.rs @@ -335,7 +335,7 @@ fn parse(tcx: TyCtxt<'tcx>, def_id: DefId) -> Result { 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 { diff --git a/src/librustc_mir/dataflow/mod.rs b/src/librustc_mir/dataflow/mod.rs index 8a9edb23a10..fdec5729a54 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/src/librustc_mir/dataflow/mod.rs @@ -1,5 +1,6 @@ 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::*; @@ -28,9 +29,13 @@ pub struct MoveDataParamEnv<'tcx> { pub(crate) param_env: ty::ParamEnv<'tcx>, } -pub(crate) fn has_rustc_mir_with(attrs: &[ast::Attribute], name: Symbol) -> Option { +pub(crate) fn has_rustc_mir_with( + sess: &Session, + attrs: &[ast::Attribute], + name: Symbol, +) -> Option { 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() { diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs index a9e6e324eb2..7dfa913fd08 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/src/librustc_mir/interpret/memory.rs @@ -952,7 +952,7 @@ pub fn copy_repeatedly( if compressed.no_bytes_init() { // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range - // is marked as unititialized but we otherwise omit changing the byte representation which may + // is marked as uninitialized but we otherwise omit changing the byte representation which may // be arbitrary for uninitialized bytes. // This also avoids writing to the target bytes so that the backing allocation is never // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary diff --git a/src/librustc_mir/interpret/util.rs b/src/librustc_mir/interpret/util.rs index c0eac8a9305..57c5fc59cc0 100644 --- a/src/librustc_mir/interpret/util.rs +++ b/src/librustc_mir/interpret/util.rs @@ -47,14 +47,26 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { unused_params.contains(index).map(|unused| !unused).unwrap_or(true); // Only recurse when generic parameters in fns, closures and generators // are used and require substitution. - if is_used && subst.needs_subst() { + match (is_used, subst.needs_subst()) { // Just in case there are closures or generators within this subst, // recurse. - if subst.super_visit_with(self) { + (true, true) if subst.super_visit_with(self) => { // Only return when we find a parameter so the remaining substs // are not skipped. return true; } + // Confirm that polymorphization replaced the parameter with + // `ty::Param`/`ty::ConstKind::Param`. + (false, true) if cfg!(debug_assertions) => match subst.unpack() { + ty::subst::GenericArgKind::Type(ty) => { + assert!(matches!(ty.kind, ty::Param(_))) + } + ty::subst::GenericArgKind::Const(ct) => { + assert!(matches!(ct.val, ty::ConstKind::Param(_))) + } + ty::subst::GenericArgKind::Lifetime(..) => (), + }, + _ => {} } } false diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/src/librustc_mir/monomorphize/polymorphize.rs index 562f512c5da..a996b6fb9d9 100644 --- a/src/librustc_mir/monomorphize/polymorphize.rs +++ b/src/librustc_mir/monomorphize/polymorphize.rs @@ -15,6 +15,7 @@ self, fold::{TypeFoldable, TypeVisitor}, query::Providers, + subst::SubstsRef, Const, Ty, TyCtxt, }; use rustc_span::symbol::sym; @@ -28,7 +29,7 @@ pub fn provide(providers: &mut Providers) { /// Determine which generic parameters are used by the function/method/closure represented by /// `def_id`. Returns a bitset where bits representing unused parameters are set (`is_empty` /// indicates all parameters are used). -fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { +fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { debug!("unused_generic_params({:?})", def_id); if !tcx.sess.opts.debugging_opts.polymorphize { @@ -36,6 +37,13 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { return FiniteBitSet::new_empty(); } + // Polymorphization results are stored in cross-crate metadata only when there are unused + // parameters, so assume that non-local items must have only used parameters (else this query + // would not be invoked, and the cross-crate metadata used instead). + if !def_id.is_local() { + return FiniteBitSet::new_empty(); + } + let generics = tcx.generics_of(def_id); debug!("unused_generic_params: generics={:?}", generics); @@ -53,7 +61,7 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet { // Create a bitset with N rightmost ones for each parameter. let generics_count: u32 = generics.count().try_into().expect("more generic parameters than can fit into a `u32`"); - let mut unused_parameters = FiniteBitSet::::new_empty(); + let mut unused_parameters = FiniteBitSet::::new_empty(); unused_parameters.set_range(0..generics_count); debug!("unused_generic_params: (start) unused_parameters={:?}", unused_parameters); mark_used_by_default_parameters(tcx, def_id, generics, &mut unused_parameters); @@ -84,7 +92,7 @@ fn mark_used_by_default_parameters<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, generics: &'tcx ty::Generics, - unused_parameters: &mut FiniteBitSet, + unused_parameters: &mut FiniteBitSet, ) { if !tcx.is_trait(def_id) && (tcx.is_closure(def_id) || tcx.type_of(def_id).is_generator()) { for param in &generics.params { @@ -110,11 +118,11 @@ fn mark_used_by_default_parameters<'tcx>( fn mark_used_by_predicates<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, - unused_parameters: &mut FiniteBitSet, + unused_parameters: &mut FiniteBitSet, ) { let def_id = tcx.closure_base_def_id(def_id); - let is_self_ty_used = |unused_parameters: &mut FiniteBitSet, self_ty: Ty<'tcx>| { + let is_self_ty_used = |unused_parameters: &mut FiniteBitSet, self_ty: Ty<'tcx>| { debug!("unused_generic_params: self_ty={:?}", self_ty); if let ty::Param(param) = self_ty.kind { !unused_parameters.contains(param.index).unwrap_or(false) @@ -123,7 +131,7 @@ fn mark_used_by_predicates<'tcx>( } }; - let mark_ty = |unused_parameters: &mut FiniteBitSet, ty: Ty<'tcx>| { + let mark_ty = |unused_parameters: &mut FiniteBitSet, ty: Ty<'tcx>| { let mut vis = UsedGenericParametersVisitor { tcx, def_id, unused_parameters }; ty.visit_with(&mut vis); }; @@ -159,11 +167,15 @@ fn emit_unused_generic_params_error<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, generics: &'tcx ty::Generics, - unused_parameters: &FiniteBitSet, + unused_parameters: &FiniteBitSet, ) { 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; } @@ -195,7 +207,26 @@ fn emit_unused_generic_params_error<'tcx>( struct UsedGenericParametersVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, def_id: DefId, - unused_parameters: &'a mut FiniteBitSet, + unused_parameters: &'a mut FiniteBitSet, +} + +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> { @@ -238,6 +269,17 @@ fn visit_const(&mut self, c: &'tcx Const<'tcx>) -> bool { 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), } } @@ -258,19 +300,7 @@ fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { // 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) => { diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 8e2fd709d66..db0b0415728 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -34,7 +34,9 @@ }; 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. @@ -155,14 +157,19 @@ struct ConstPropMachine<'mir, 'tcx> { written_only_inside_own_block_locals: FxHashSet, /// Locals that need to be cleared after every block terminates. only_propagate_inside_block_locals: BitSet, + can_const_prop: IndexVec, } impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> { - fn new(only_propagate_inside_block_locals: BitSet) -> Self { + fn new( + only_propagate_inside_block_locals: BitSet, + can_const_prop: IndexVec, + ) -> Self { Self { stack: Vec::new(), written_only_inside_own_block_locals: Default::default(), only_propagate_inside_block_locals, + can_const_prop, } } } @@ -241,6 +248,9 @@ fn access_local_mut<'a>( local: Local, ) -> InterpResult<'tcx, Result<&'a mut LocalValue, MemPlace>> { + 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); } @@ -285,7 +295,6 @@ fn stack_mut( struct ConstPropagator<'mir, 'tcx> { ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, tcx: TyCtxt<'tcx>, - can_const_prop: IndexVec, param_env: ParamEnv<'tcx>, // FIXME(eddyb) avoid cloning these two fields more than once, // by accessing them through `ecx` instead. @@ -331,7 +340,10 @@ fn new( 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 { @@ -342,7 +354,7 @@ fn new( tcx, span, param_env, - ConstPropMachine::new(only_propagate_inside_block_locals), + ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop), (), ); @@ -368,7 +380,6 @@ fn new( 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(), @@ -612,15 +623,9 @@ fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) { 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 @@ -893,7 +898,11 @@ struct CanConstProp { impl CanConstProp { /// Returns true if `local` can be propagated - fn check(body: &Body<'_>) -> IndexVec { + fn check( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + body: &Body<'tcx>, + ) -> IndexVec { let mut cpv = CanConstProp { can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls), found_assignment: BitSet::new_empty(body.local_decls.len()), @@ -903,6 +912,16 @@ fn check(body: &Body<'_>) -> IndexVec { ), }; 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 @@ -1018,61 +1037,52 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio 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); diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs index fe63a67fdbb..5b2954dd5b0 100644 --- a/src/librustc_mir/transform/instrument_coverage.rs +++ b/src/librustc_mir/transform/instrument_coverage.rs @@ -5,18 +5,19 @@ use rustc_hir::lang_items; use rustc_middle::hir; use rustc_middle::ich::StableHashingContext; +use rustc_middle::mir; use rustc_middle::mir::coverage::*; use rustc_middle::mir::interpret::Scalar; +use rustc_middle::mir::traversal; use rustc_middle::mir::{ - self, traversal, BasicBlock, BasicBlockData, CoverageInfo, Operand, Place, SourceInfo, - SourceScope, StatementKind, Terminator, TerminatorKind, + BasicBlock, BasicBlockData, CoverageInfo, Operand, Place, SourceInfo, SourceScope, + StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::FnDef; -use rustc_middle::ty::TyCtxt; +use rustc_middle::ty::{FnDef, TyCtxt}; use rustc_span::def_id::DefId; -use rustc_span::{Pos, Span}; +use rustc_span::{FileName, Pos, RealFileName, Span}; /// Inserts call to count_code_region() as a placeholder to be replaced during code generation with /// the intrinsic llvm.instrprof.increment. @@ -112,6 +113,7 @@ enum Op { struct InjectedCall<'tcx> { func: Operand<'tcx>, args: Vec>, + span: Span, inject_at: Span, } @@ -179,12 +181,11 @@ fn inject_counters(&mut self) { let _ignore = mir_body; let id = self.next_counter(); let function_source_hash = self.function_source_hash(); - let code_region = body_span; let scope = rustc_middle::mir::OUTERMOST_SOURCE_SCOPE; let is_cleanup = false; let next_block = rustc_middle::mir::START_BLOCK; self.inject_call( - self.make_counter(id, function_source_hash, code_region), + self.make_counter(id, function_source_hash, body_span), scope, is_cleanup, next_block, @@ -201,14 +202,13 @@ fn inject_counters(&mut self) { let op = if add { Op::Add } else { Op::Subtract }; let rhs = 2; - let code_region = body_span; let scope = rustc_middle::mir::OUTERMOST_SOURCE_SCOPE; let is_cleanup = false; let next_block = rustc_middle::mir::START_BLOCK; let id = self.next_expression(); self.inject_call( - self.make_expression(id, code_region, lhs, op, rhs), + self.make_expression(id, body_span, lhs, op, rhs), scope, is_cleanup, next_block, @@ -216,13 +216,8 @@ fn inject_counters(&mut self) { } } - fn make_counter( - &self, - id: u32, - function_source_hash: u64, - code_region: Span, - ) -> InjectedCall<'tcx> { - let inject_at = code_region.shrink_to_lo(); + fn make_counter(&self, id: u32, function_source_hash: u64, span: Span) -> InjectedCall<'tcx> { + let inject_at = span.shrink_to_lo(); let func = function_handle( self.tcx, @@ -239,24 +234,18 @@ fn make_counter( debug_assert_eq!(COUNTER_ID, args.len()); args.push(self.const_u32(id, inject_at)); - debug_assert_eq!(START_BYTE_POS, args.len()); - args.push(self.const_u32(code_region.lo().to_u32(), inject_at)); - - debug_assert_eq!(END_BYTE_POS, args.len()); - args.push(self.const_u32(code_region.hi().to_u32(), inject_at)); - - InjectedCall { func, args, inject_at } + InjectedCall { func, args, span, inject_at } } fn make_expression( &self, id: u32, - code_region: Span, + span: Span, lhs: u32, op: Op, rhs: u32, ) -> InjectedCall<'tcx> { - let inject_at = code_region.shrink_to_lo(); + let inject_at = span.shrink_to_lo(); let func = function_handle( self.tcx, @@ -282,13 +271,7 @@ fn make_expression( debug_assert_eq!(RIGHT_ID, args.len()); args.push(self.const_u32(rhs, inject_at)); - debug_assert_eq!(START_BYTE_POS, args.len()); - args.push(self.const_u32(code_region.lo().to_u32(), inject_at)); - - debug_assert_eq!(END_BYTE_POS, args.len()); - args.push(self.const_u32(code_region.hi().to_u32(), inject_at)); - - InjectedCall { func, args, inject_at } + InjectedCall { func, args, span, inject_at } } fn inject_call( @@ -298,7 +281,7 @@ fn inject_call( is_cleanup: bool, next_block: BasicBlock, ) { - let InjectedCall { func, args, inject_at } = call; + let InjectedCall { func, mut args, span, inject_at } = call; debug!( " injecting {}call to {:?}({:?}) at: {:?}, scope: {:?}", if is_cleanup { "cleanup " } else { "" }, @@ -310,6 +293,14 @@ fn inject_call( let mut patch = MirPatch::new(self.mir_body); + let (file_name, start_line, start_col, end_line, end_col) = self.code_region(&span); + + args.push(self.const_str(&file_name, inject_at)); + args.push(self.const_u32(start_line, inject_at)); + args.push(self.const_u32(start_col, inject_at)); + args.push(self.const_u32(end_line, inject_at)); + args.push(self.const_u32(end_col, inject_at)); + let temp = patch.new_temp(self.tcx.mk_unit(), inject_at); let new_block = patch.new_block(placeholder_block(inject_at, scope, is_cleanup)); patch.patch_terminator( @@ -335,6 +326,43 @@ fn inject_call( self.mir_body.basic_blocks_mut().swap(next_block, new_block); } + /// Convert the Span into its file name, start line and column, and end line and column + fn code_region(&self, span: &Span) -> (String, u32, u32, u32, u32) { + let source_map = self.tcx.sess.source_map(); + let start = source_map.lookup_char_pos(span.lo()); + let end = if span.hi() == span.lo() { + start.clone() + } else { + let end = source_map.lookup_char_pos(span.hi()); + debug_assert_eq!( + start.file.name, + end.file.name, + "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!", + span.lo(), + start, + span.hi(), + end + ); + end + }; + match &start.file.name { + FileName::Real(RealFileName::Named(path)) => ( + path.to_string_lossy().to_string(), + start.line as u32, + start.col.to_u32() + 1, + end.line as u32, + end.col.to_u32() + 1, + ), + _ => { + bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name) + } + } + } + + fn const_str(&self, value: &str, span: Span) -> Operand<'tcx> { + Operand::const_from_str(self.tcx, value, span) + } + fn const_u32(&self, value: u32, span: Span) -> Operand<'tcx> { Operand::const_from_scalar(self.tcx, self.tcx.types.u32, Scalar::from_u32(value), span) } diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index f1a7338d11f..c0564105701 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/src/librustc_mir/transform/promote_consts.rs @@ -130,7 +130,7 @@ fn forces_explicit_promotion(&self) -> bool { fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { 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 { diff --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs index de7d7f27186..dfd01e27d57 100644 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ b/src/librustc_mir/transform/qualify_min_const_fn.rs @@ -193,7 +193,15 @@ fn check_rvalue( _, ) => Err((span, "function pointer casts are not allowed in const fn".into())), Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), op, cast_ty) => { - let pointee_ty = cast_ty.builtin_deref(true).unwrap().ty; + let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) { + deref_ty.ty + } else { + // We cannot allow this for now. + return Err(( + span, + "unsizing casts are only allowed for references right now".into(), + )); + }; let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); if let ty::Slice(_) | ty::Str = unsized_ty.kind { check_operand(tcx, op, span, def_id, body)?; @@ -334,7 +342,7 @@ fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bo // 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)) } @@ -354,7 +362,7 @@ pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbo // 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)) } diff --git a/src/librustc_mir/transform/rustc_peek.rs b/src/librustc_mir/transform/rustc_peek.rs index 5eb374e7ee2..729e22a94dc 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/src/librustc_mir/transform/rustc_peek.rs @@ -35,8 +35,9 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx 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(); @@ -44,7 +45,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx 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(); @@ -52,7 +53,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx 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(); @@ -60,7 +61,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx 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(); @@ -68,14 +69,14 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx 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"); } } diff --git a/src/librustc_mir/transform/simplify_try.rs b/src/librustc_mir/transform/simplify_try.rs index 97a01de867e..02896d7de35 100644 --- a/src/librustc_mir/transform/simplify_try.rs +++ b/src/librustc_mir/transform/simplify_try.rs @@ -361,7 +361,7 @@ fn optimization_applies<'tcx>( } trace!("SUCCESS: optimization applies!"); - return true; + true } impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { diff --git a/src/librustc_mir/transform/validate.rs b/src/librustc_mir/transform/validate.rs index b8a74f09409..9296e2ca700 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/src/librustc_mir/transform/validate.rs @@ -115,7 +115,7 @@ fn binders( T: Relate<'tcx>, { self.relate(a.skip_binder(), b.skip_binder())?; - Ok(a.clone()) + Ok(a) } } diff --git a/src/librustc_mir_build/build/mod.rs b/src/librustc_mir_build/build/mod.rs index 3c4587119cd..f3f3c3e33a4 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/src/librustc_mir_build/build/mod.rs @@ -537,7 +537,7 @@ macro_rules! unpack { 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 { diff --git a/src/librustc_mir_build/thir/cx/mod.rs b/src/librustc_mir_build/thir/cx/mod.rs index 21736df7b07..bb814ab8248 100644 --- a/src/librustc_mir_build/thir/cx/mod.rs +++ b/src/librustc_mir_build/thir/cx/mod.rs @@ -6,7 +6,6 @@ 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; @@ -69,7 +68,7 @@ impl<'a, 'tcx> Cx<'a, 'tcx> { // 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(); diff --git a/src/librustc_parse/lexer/mod.rs b/src/librustc_parse/lexer/mod.rs index 2b0e637c74e..c3a79660eb9 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/src/librustc_parse/lexer/mod.rs @@ -1,4 +1,4 @@ -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}; @@ -170,22 +170,20 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Tok 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" @@ -202,9 +200,15 @@ fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Tok 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 } diff --git a/src/librustc_parse/lib.rs b/src/librustc_parse/lib.rs index 3319ca44da4..723e4333790 100644 --- a/src/librustc_parse/lib.rs +++ b/src/librustc_parse/lib.rs @@ -486,7 +486,9 @@ fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool { (&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, @@ -524,7 +526,7 @@ fn prepend_attrs( 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; diff --git a/src/librustc_parse/parser/attr.rs b/src/librustc_parse/parser/attr.rs index 8b67f4743c6..b6a8ee71beb 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/src/librustc_parse/parser/attr.rs @@ -2,10 +2,9 @@ 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; @@ -47,8 +46,8 @@ pub(super) fn parse_outer_attributes(&mut self) -> PResult<'a, Vec PResult<'a, Vec 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 @@ -184,9 +179,9 @@ pub fn parse_attr_item(&mut self) -> PResult<'a, ast::AttrItem> { 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(); diff --git a/src/librustc_parse/parser/diagnostics.rs b/src/librustc_parse/parser/diagnostics.rs index 5e9411327ca..2854356ab0f 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/src/librustc_parse/parser/diagnostics.rs @@ -1419,7 +1419,7 @@ pub(super) fn expected_semi_or_open_brace(&mut self) -> PResult<'a, T> { } 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", diff --git a/src/librustc_parse/parser/generics.rs b/src/librustc_parse/parser/generics.rs index 47794746126..be72ed6dffb 100644 --- a/src/librustc_parse/parser/generics.rs +++ b/src/librustc_parse/parser/generics.rs @@ -54,7 +54,7 @@ fn parse_const_param(&mut self, preceding_attrs: Vec) -> PResult<'a, 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, diff --git a/src/librustc_parse/parser/item.rs b/src/librustc_parse/parser/item.rs index 5923a185dcf..10d214e52ab 100644 --- a/src/librustc_parse/parser/item.rs +++ b/src/librustc_parse/parser/item.rs @@ -610,7 +610,7 @@ fn parse_item_list( /// 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(), @@ -1231,7 +1231,7 @@ fn parse_single_struct_field( 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 diff --git a/src/librustc_parse/parser/mod.rs b/src/librustc_parse/parser/mod.rs index 2509a979221..b33ae4bed82 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/src/librustc_parse/parser/mod.rs @@ -22,7 +22,6 @@ 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; @@ -104,6 +103,8 @@ pub struct Parser<'a> { /// error. pub(super) unclosed_delims: Vec, last_unexpected_token_span: Option, + /// 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>, @@ -209,18 +210,18 @@ fn next(&mut self) -> Token { } 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, @@ -236,10 +237,7 @@ fn next_desugared(&mut self) -> Token { [ 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() @@ -251,7 +249,7 @@ fn next_desugared(&mut self) -> Token { 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() diff --git a/src/librustc_parse_format/lib.rs b/src/librustc_parse_format/lib.rs index 7db62f3493e..ebb3aa3866e 100644 --- a/src/librustc_parse_format/lib.rs +++ b/src/librustc_parse_format/lib.rs @@ -820,7 +820,7 @@ fn find_skips(snippet: &str, is_raw: bool) -> Vec { } 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) } diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index 1ff47ee038d..d438fe35ff4 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -9,7 +9,6 @@ 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; @@ -60,17 +59,17 @@ fn check_attributes( ) { 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 @@ -144,7 +143,7 @@ fn check_track_caller( 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, @@ -262,7 +261,7 @@ fn check_repr( // ``` 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(); @@ -391,10 +390,10 @@ fn check_stmt_attributes(&self, stmt: &hir::Stmt<'_>) { // 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, @@ -412,10 +411,10 @@ fn check_expr_attributes(&self, expr: &hir::Expr<'_>) { _ => 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, @@ -431,7 +430,7 @@ fn check_expr_attributes(&self, expr: &hir::Expr<'_>) { 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"); diff --git a/src/librustc_passes/check_const.rs b/src/librustc_passes/check_const.rs index b1ebab3f2f8..dd0bcbf208d 100644 --- a/src/librustc_passes/check_const.rs +++ b/src/librustc_passes/check_const.rs @@ -106,7 +106,7 @@ fn const_check_violated(&self, expr: NonConstExpr, span: Span) { // 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)) }; diff --git a/src/librustc_passes/dead.rs b/src/librustc_passes/dead.rs index ab75c8ebf4c..0e5298acc2c 100644 --- a/src/librustc_passes/dead.rs +++ b/src/librustc_passes/dead.rs @@ -15,7 +15,7 @@ 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 @@ -331,17 +331,17 @@ fn has_allow_dead_code_or_lang_attr( 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; } diff --git a/src/librustc_passes/diagnostic_items.rs b/src/librustc_passes/diagnostic_items.rs index 3cce4b8d00e..fa59337b0f6 100644 --- a/src/librustc_passes/diagnostic_items.rs +++ b/src/librustc_passes/diagnostic_items.rs @@ -16,6 +16,7 @@ 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> { @@ -44,7 +45,7 @@ fn new(tcx: TyCtxt<'tcx>) -> 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()); @@ -86,9 +87,9 @@ fn collect_item( } /// Extract the first `rustc_diagnostic_item = "$name"` out of a list of attributes. -fn extract(attrs: &[ast::Attribute]) -> Option { +fn extract(sess: &Session, attrs: &[ast::Attribute]) -> Option { 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 } }) } diff --git a/src/librustc_passes/entry.rs b/src/librustc_passes/entry.rs index 11612101e37..8aa6e7936be 100644 --- a/src/librustc_passes/entry.rs +++ b/src/librustc_passes/entry.rs @@ -1,4 +1,3 @@ -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}; @@ -58,7 +57,7 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType) } // 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; } @@ -76,14 +75,14 @@ fn entry_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option<(LocalDefId, EntryFnType) 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 { @@ -101,7 +100,7 @@ fn entry_point_type(item: &Item<'_>, at_root: bool) -> EntryPointType { } 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)); diff --git a/src/librustc_passes/lang_items.rs b/src/librustc_passes/lang_items.rs index e07c71b41d8..07415870549 100644 --- a/src/librustc_passes/lang_items.rs +++ b/src/librustc_passes/lang_items.rs @@ -56,7 +56,8 @@ fn new(tcx: TyCtxt<'tcx>) -> LanguageItemCollector<'tcx> { } 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 => { diff --git a/src/librustc_passes/layout_test.rs b/src/librustc_passes/layout_test.rs index 55a6d3f7645..9450d75620a 100644 --- a/src/librustc_passes/layout_test.rs +++ b/src/librustc_passes/layout_test.rs @@ -29,7 +29,7 @@ fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { | 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); } } diff --git a/src/librustc_passes/lib_features.rs b/src/librustc_passes/lib_features.rs index 922a475e5f4..9a4aa6a68a6 100644 --- a/src/librustc_passes/lib_features.rs +++ b/src/librustc_passes/lib_features.rs @@ -34,7 +34,9 @@ fn extract(&self, attr: &Attribute) -> Option<(Symbol, Option, Span)> { // 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; diff --git a/src/librustc_passes/liveness.rs b/src/librustc_passes/liveness.rs index 45193c45569..6477f8da008 100644 --- a/src/librustc_passes/liveness.rs +++ b/src/librustc_passes/liveness.rs @@ -355,7 +355,7 @@ fn visit_fn<'tcx>( 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; } } diff --git a/src/librustc_passes/stability.rs b/src/librustc_passes/stability.rs index 830af8d31e7..1af77ae61c7 100644 --- a/src/librustc_passes/stability.rs +++ b/src/librustc_passes/stability.rs @@ -65,11 +65,8 @@ fn annotate( 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; @@ -88,7 +85,7 @@ fn annotate( } 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; \ @@ -105,7 +102,7 @@ fn annotate( 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); @@ -252,7 +249,7 @@ fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> boo 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, diff --git a/src/librustc_passes/weak_lang_items.rs b/src/librustc_passes/weak_lang_items.rs index 3b11fb37962..2749b96bc85 100644 --- a/src/librustc_passes/weak_lang_items.rs +++ b/src/librustc_passes/weak_lang_items.rs @@ -100,7 +100,8 @@ fn nested_visit_map(&mut self) -> NestedVisitorMap { } 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) diff --git a/src/librustc_plugin_impl/build.rs b/src/librustc_plugin_impl/build.rs index db2363316cd..d16dd701a12 100644 --- a/src/librustc_plugin_impl/build.rs +++ b/src/librustc_plugin_impl/build.rs @@ -1,6 +1,5 @@ //! 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; @@ -9,14 +8,15 @@ 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)); } } @@ -35,7 +35,7 @@ pub fn find_plugin_registrar(tcx: TyCtxt<'_>) -> Option { fn plugin_registrar_fn(tcx: TyCtxt<'_>, cnum: CrateNum) -> Option { 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() { diff --git a/src/librustc_plugin_impl/lib.rs b/src/librustc_plugin_impl/lib.rs index 10712eb60b9..1eb65dd96ba 100644 --- a/src/librustc_plugin_impl/lib.rs +++ b/src/librustc_plugin_impl/lib.rs @@ -8,6 +8,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] #![feature(nll)] +#![recursion_limit = "256"] use rustc_lint::LintStore; diff --git a/src/librustc_plugin_impl/load.rs b/src/librustc_plugin_impl/load.rs index 62a87b47a2f..2f307302db0 100644 --- a/src/librustc_plugin_impl/load.rs +++ b/src/librustc_plugin_impl/load.rs @@ -32,7 +32,7 @@ pub fn load_plugins( let mut plugins = Vec::new(); for attr in &krate.attrs { - if !attr.check_name(sym::plugin) { + if !sess.check_name(attr, sym::plugin) { continue; } diff --git a/src/librustc_privacy/lib.rs b/src/librustc_privacy/lib.rs index fc00050f405..2aa7780aaaf 100644 --- a/src/librustc_privacy/lib.rs +++ b/src/librustc_privacy/lib.rs @@ -232,7 +232,7 @@ fn def_id_visibility<'tcx>( 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 @@ -271,8 +271,11 @@ fn def_id_visibility<'tcx>( 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"; } @@ -305,7 +308,9 @@ fn def_id_visibility<'tcx>( 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"; @@ -914,7 +919,9 @@ fn visit_mod(&mut self, m: &'tcx hir::Mod<'tcx>, _sp: Span, id: hir::HirId) { } 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; } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index 737fd138120..11c7793b3ad 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -541,7 +541,7 @@ fn build_reduced_graph_for_use_tree( } 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); @@ -712,7 +712,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) { 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), @@ -789,7 +789,7 @@ fn build_reduced_graph_for_item(&mut self, item: &'b Item) { // 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 { @@ -991,7 +991,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool 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, @@ -1097,7 +1097,7 @@ fn process_macro_use_imports(&mut self, item: &Item, module: Module<'a>) -> bool /// 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 { @@ -1105,7 +1105,7 @@ fn contains_macro_use(&mut self, attrs: &[ast::Attribute]) -> bool { } else { err.emit(); } - } else if !attr.check_name(sym::macro_use) { + } else if !self.r.session.check_name(attr, sym::macro_use) { continue; } @@ -1129,12 +1129,13 @@ fn visit_invoc(&mut self, id: NodeId) -> MacroRulesScope<'a> { 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)); @@ -1168,7 +1169,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScope<'a> { 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) @@ -1185,7 +1186,7 @@ fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScope<'a> { 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 { @@ -1416,7 +1417,7 @@ fn visit_variant(&mut self, variant: &'b ast::Variant) { // 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)); } diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 81e29047dc5..9502be728de 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -466,6 +466,23 @@ impl<'a> Resolver<'a> { ); 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, @@ -1075,10 +1092,9 @@ fn ctor_fields_span(&self, binding: &NameBinding<'_>) -> Option { ) = 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 } diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index 44ff4209095..7ecfe2554ec 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -111,7 +111,7 @@ enum PatBoundCtx { 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>), @@ -137,7 +137,7 @@ impl RibKind<'_> { NormalRibKind | ClosureOrAsyncRibKind | FnItemRibKind - | ConstantItemRibKind + | ConstantItemRibKind(_) | ModuleRibKind(_) | MacroDefinition(_) | ConstParamTyRibKind => false, @@ -226,7 +226,7 @@ fn descr_expected(self) -> &'static str { 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 { @@ -426,7 +426,7 @@ fn visit_block(&mut self, block: &'ast Block) { } 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); }); } @@ -628,7 +628,7 @@ fn visit_generic_arg(&mut self, arg: &'ast GenericArg) { 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(), @@ -829,7 +829,7 @@ fn is_label_valid_from_rib(&self, rib_index: usize) -> bool { | ClosureOrAsyncRibKind | FnItemRibKind | ItemRibKind(..) - | ConstantItemRibKind + | ConstantItemRibKind(_) | ModuleRibKind(..) | ForwardTyParamBanRibKind | ConstParamTyRibKind => { @@ -948,7 +948,14 @@ fn resolve_item(&mut self, item: &'ast Item) { // 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, _) => { @@ -989,7 +996,9 @@ fn resolve_item(&mut self, item: &'ast Item) { 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) + }); } }); } @@ -1086,11 +1095,11 @@ fn with_item_rib(&mut self, has_generic_params: HasGenericParams, f: impl FnOnce 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); }) }); } @@ -1220,7 +1229,7 @@ fn resolve_implementation( 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 @@ -1231,7 +1240,12 @@ fn resolve_implementation( |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) }); } diff --git a/src/librustc_resolve/late/lifetimes.rs b/src/librustc_resolve/late/lifetimes.rs index 3fbb42ece47..0b881b089de 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/src/librustc_resolve/late/lifetimes.rs @@ -6,7 +6,6 @@ //! 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}; @@ -1179,7 +1178,7 @@ fn compute_object_lifetime_defaults(tcx: TyCtxt<'_>) -> HirIdMap { 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 @@ -1194,7 +1197,7 @@ pub fn new( 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); @@ -1232,9 +1235,9 @@ pub fn new( .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()); @@ -2507,7 +2510,7 @@ fn validate_res_from_ribs( res_err = Some(CannotCaptureDynamicEnvironmentInFnItem); } } - ConstantItemRibKind => { + ConstantItemRibKind(_) => { // Still doesn't deal with upvars if record_used { self.report_error(span, AttemptToUseNonConstantValueInConstant); @@ -2546,7 +2549,18 @@ fn validate_res_from_ribs( 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( @@ -2612,7 +2626,18 @@ fn validate_res_from_ribs( 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( diff --git a/src/librustc_resolve/macros.rs b/src/librustc_resolve/macros.rs index ccc7e16ae4c..542025ac1f4 100644 --- a/src/librustc_resolve/macros.rs +++ b/src/librustc_resolve/macros.rs @@ -9,7 +9,7 @@ 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; @@ -105,7 +105,7 @@ fn registered_idents( descr: &str, ) -> FxHashSet { 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) => { @@ -1068,7 +1068,7 @@ fn prohibit_imported_non_macro_attrs( /// 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, diff --git a/src/librustc_save_analysis/lib.rs b/src/librustc_save_analysis/lib.rs index 8e379a35100..6469971fce8 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/src/librustc_save_analysis/lib.rs @@ -10,7 +10,7 @@ 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}; @@ -702,7 +702,7 @@ fn fn_type(seg: &hir::PathSegment<'_>) -> bool { 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. @@ -822,13 +822,10 @@ fn docs_for_attrs(&self, attrs: &[ast::Attribute]) -> String { 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() diff --git a/src/librustc_session/filesearch.rs b/src/librustc_session/filesearch.rs index 504490d938c..8fe71b71cae 100644 --- a/src/librustc_session/filesearch.rs +++ b/src/librustc_session/filesearch.rs @@ -98,7 +98,7 @@ pub fn get_tools_search_paths(&self, self_contained: bool) -> Vec { 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] } } } diff --git a/src/librustc_session/output.rs b/src/librustc_session/output.rs index 52216188397..e4bce435c4b 100644 --- a/src/librustc_session/output.rs +++ b/src/librustc_session/output.rs @@ -1,7 +1,7 @@ //! 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}; @@ -45,7 +45,7 @@ fn is_writeable(p: &Path) -> bool { } } -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| { validate_crate_name(sess, &s, span); s @@ -56,22 +56,20 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: // 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 { @@ -85,9 +83,7 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: `{}` has a leading hyphen", s ); - if let Some(sess) = sess { - sess.err(&msg); - } + sess.err(&msg); } else { return validate(s.replace("-", "_"), None); } @@ -97,14 +93,13 @@ pub fn find_crate_name(sess: Option<&Session>, attrs: &[ast::Attribute], input: "rust_out".to_string() } -pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { +pub fn validate_crate_name(sess: &Session, s: &str, sp: Option) { 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; }; @@ -123,7 +118,7 @@ pub fn validate_crate_name(sess: Option<&Session>, s: &str, sp: Option) { } if err_count > 0 { - sess.unwrap().abort_if_errors(); + sess.abort_if_errors(); } } diff --git a/src/librustc_session/session.rs b/src/librustc_session/session.rs index e9077f40859..9191f7e8d76 100644 --- a/src/librustc_session/session.rs +++ b/src/librustc_session/session.rs @@ -7,6 +7,8 @@ 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}; @@ -22,7 +24,7 @@ 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}; @@ -208,6 +210,9 @@ pub struct Session { /// Set of enabled features for the current target. pub target_features: FxHashSet, + + known_attrs: Lock, + used_attrs: Lock, } pub struct PerfStats { @@ -1020,6 +1025,76 @@ pub fn emit_lifetime_markers(&self) -> bool { // 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 { + attrs.iter().filter(move |attr| self.check_name(attr, name)) + } + + pub fn first_attr_value_str_by_name( + &self, + attrs: &[Attribute], + name: Symbol, + ) -> Option { + attrs.iter().find(|at| self.check_name(at, name)).and_then(|at| at.value_str()) + } } fn default_emitter( @@ -1283,6 +1358,8 @@ pub fn build_session( 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); diff --git a/src/librustc_span/hygiene.rs b/src/librustc_span/hygiene.rs index 74dc904b6e6..f52b2195c2f 100644 --- a/src/librustc_span/hygiene.rs +++ b/src/librustc_span/hygiene.rs @@ -80,8 +80,6 @@ pub enum Transparency { Opaque, } -pub(crate) const NUM_TRANSPARENCIES: usize = 3; - impl ExpnId { pub fn fresh(expn_data: Option) -> Self { HygieneData::with(|data| data.fresh_expn(expn_data)) @@ -618,6 +616,11 @@ pub fn outer_expn_data(self) -> ExpnData { 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| { @@ -667,7 +670,6 @@ pub struct ExpnData { /// 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 {}` @@ -1030,7 +1032,7 @@ pub fn decode_expn_id< drop(expns); expn_id }); - return Ok(expn_id); + Ok(expn_id) } // Decodes `SyntaxContext`, using the provided `HygieneDecodeContext` @@ -1103,7 +1105,7 @@ pub fn decode_syntax_context< assert_eq!(dummy.dollar_crate_name, kw::Invalid); }); - return Ok(new_ctxt); + Ok(new_ctxt) } pub fn num_syntax_ctxts() -> usize { diff --git a/src/librustc_span/lib.rs b/src/librustc_span/lib.rs index 7087dc80b1d..697d88ad063 100644 --- a/src/librustc_span/lib.rs +++ b/src/librustc_span/lib.rs @@ -32,8 +32,8 @@ 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; @@ -87,6 +87,15 @@ pub fn new(edition: Edition) -> SessionGlobals { } } +pub fn with_session_globals(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(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. @@ -1814,47 +1823,51 @@ fn hash_stable(&self, ctx: &mut CTX, hasher: &mut StableHasher) { 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; NUM_TRANSPARENCIES]>>> = Default::default(); - } +impl HashStable 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>> = 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); } } diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 98776a04782..5203bfdb3b7 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -672,6 +672,7 @@ min_align_of, min_align_of_val, min_const_fn, + min_const_generics, min_const_unsafe_fn, min_specialization, minnumf32, diff --git a/src/librustc_symbol_mangling/test.rs b/src/librustc_symbol_mangling/test.rs index 2f1c896ce2f..24850a8a0d2 100644 --- a/src/librustc_symbol_mangling/test.rs +++ b/src/librustc_symbol_mangling/test.rs @@ -34,16 +34,16 @@ fn process_attrs(&mut self, hir_id: hir::HirId) { 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)); } diff --git a/src/librustc_target/spec/wasm32_base.rs b/src/librustc_target/spec/wasm32_base.rs index 8423573b52d..62fc8f06183 100644 --- a/src/librustc_target/spec/wasm32_base.rs +++ b/src/librustc_target/spec/wasm32_base.rs @@ -10,13 +10,6 @@ pub fn options() -> TargetOptions { clang_args.push(format!("-Wl,{}", arg)); }; - // There have been reports in the wild (rustwasm/wasm-bindgen#119) of - // using threads causing weird hangs and bugs. Disable it entirely as - // this isn't yet the bottleneck of compilation at all anyway. - // - // FIXME: we should file an upstream issue with LLD about this - arg("--no-threads"); - // By default LLD only gives us one page of stack (64k) which is a // little small. Default to a larger stack closer to other PC platforms // (1MB) and users can always inject their own link-args to override this. diff --git a/src/librustc_trait_selection/autoderef.rs b/src/librustc_trait_selection/autoderef.rs index cc971440fea..02eefe56223 100644 --- a/src/librustc_trait_selection/autoderef.rs +++ b/src/librustc_trait_selection/autoderef.rs @@ -187,7 +187,7 @@ pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] { } pub fn span(&self) -> Span { - self.span.clone() + self.span } pub fn reached_recursion_limit(&self) -> bool { diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs index 13f8c71a629..e29e740f136 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/src/librustc_trait_selection/traits/error_reporting/suggestions.rs @@ -495,7 +495,7 @@ fn suggest_dereferences( 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, diff --git a/src/librustc_trait_selection/traits/on_unimplemented.rs b/src/librustc_trait_selection/traits/on_unimplemented.rs index 446d5a489df..7a9ed4b72dd 100644 --- a/src/librustc_trait_selection/traits/on_unimplemented.rs +++ b/src/librustc_trait_selection/traits/on_unimplemented.rs @@ -164,7 +164,7 @@ pub fn of_item( ) -> Result, 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); diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/src/librustc_trait_selection/traits/select/mod.rs index 75e11619924..4c575f1c6ac 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/src/librustc_trait_selection/traits/select/mod.rs @@ -24,7 +24,6 @@ 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; @@ -440,7 +439,7 @@ fn evaluate_predicate_recursively<'o>( 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. @@ -980,7 +979,7 @@ fn filter_negative_and_reservation_impls( &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!( diff --git a/src/librustc_traits/chalk/db.rs b/src/librustc_traits/chalk/db.rs index 715e5299a37..4c8be8eb610 100644 --- a/src/librustc_traits/chalk/db.rs +++ b/src/librustc_traits/chalk/db.rs @@ -141,7 +141,7 @@ fn adt_datum( 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::>>>::lower_into(wc, &self.interner)) .collect(); @@ -174,7 +174,7 @@ fn adt_datum( phantom_data: adt_def.is_phantom_data(), }, }); - return struct_datum; + struct_datum } fn fn_def_datum( @@ -187,7 +187,7 @@ 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::>>>::lower_into(wc, &self.interner)).collect(); @@ -276,7 +276,7 @@ fn impls_for_trait( 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 } @@ -379,7 +379,7 @@ fn force_impl_for( 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, @@ -398,7 +398,7 @@ fn force_impl_for( 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, @@ -440,7 +440,7 @@ fn well_known_trait_id( 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>) -> bool { diff --git a/src/librustc_ty/ty.rs b/src/librustc_ty/ty.rs index dfb28b473ff..b31f9f3c7b1 100644 --- a/src/librustc_ty/ty.rs +++ b/src/librustc_ty/ty.rs @@ -443,7 +443,7 @@ fn opaque_type_projection_predicates( 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; diff --git a/src/librustc_typeck/check/demand.rs b/src/librustc_typeck/check/demand.rs index be83ab259c2..258c5b77df2 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/src/librustc_typeck/check/demand.rs @@ -246,7 +246,7 @@ pub fn get_conversion_methods( // // 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 diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs index 88c47b38ccc..9ef91641916 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/src/librustc_typeck/check/dropck.rs @@ -368,6 +368,6 @@ fn binders( 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) } } diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index dc2172650e5..b3287caa0bf 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -379,17 +379,46 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), - sym::count_code_region => { - (0, vec![tcx.types.u64, tcx.types.u32, tcx.types.u32, tcx.types.u32], tcx.mk_unit()) - } + sym::count_code_region => ( + 0, + vec![ + tcx.types.u64, + tcx.types.u32, + tcx.mk_static_str(), + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + ], + tcx.mk_unit(), + ), sym::coverage_counter_add | sym::coverage_counter_subtract => ( 0, - vec![tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32, tcx.types.u32], + vec![ + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + tcx.mk_static_str(), + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + ], tcx.mk_unit(), ), - sym::coverage_unreachable => (0, vec![tcx.types.u32, tcx.types.u32], tcx.mk_unit()), + sym::coverage_unreachable => ( + 0, + vec![ + tcx.mk_static_str(), + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + tcx.types.u32, + ], + tcx.mk_unit(), + ), other => { struct_span_err!( diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 6cefc99f7b1..3d58fb30d91 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -2603,7 +2603,7 @@ fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { 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() { @@ -2814,7 +2814,7 @@ pub fn check_enum<'tcx>( 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, diff --git a/src/librustc_typeck/check/pat.rs b/src/librustc_typeck/check/pat.rs index 9c7ea34bf51..f598ada900f 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/src/librustc_typeck/check/pat.rs @@ -1114,7 +1114,7 @@ fn check_struct_pat_fields( 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)) => { @@ -1237,13 +1237,13 @@ fn error_inexistent_fields( 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 @@ -1299,7 +1299,7 @@ fn error_tuple_variant_as_struct_pat( fn error_unmentioned_fields( &self, - span: Span, + pat: &Pat<'_>, unmentioned_fields: &[Ident], ) -> DiagnosticBuilder<'tcx> { let field_names = if unmentioned_fields.len() == 1 { @@ -1312,23 +1312,23 @@ fn error_unmentioned_fields( .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( diff --git a/src/librustc_typeck/check/place_op.rs b/src/librustc_typeck/check/place_op.rs index 12468750923..84f34c0039a 100644 --- a/src/librustc_typeck/check/place_op.rs +++ b/src/librustc_typeck/check/place_op.rs @@ -200,13 +200,11 @@ pub fn convert_place_derefs_to_mutable(&self, expr: &hir::Expr<'_>) { // 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); diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 97df065500a..c0f56a28172 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -20,7 +20,7 @@ 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_errors::{struct_span_err, Applicability}; @@ -1238,6 +1238,9 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics { // 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)); @@ -2351,13 +2354,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { 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 { @@ -2370,9 +2373,9 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { ) .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, @@ -2394,7 +2397,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { ) .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 { @@ -2407,25 +2410,25 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { ) .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, @@ -2440,7 +2443,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } 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() { @@ -2455,11 +2458,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { &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!( @@ -2472,14 +2475,14 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { 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() { @@ -2506,11 +2509,11 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } 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!( @@ -2553,7 +2556,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { 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"); @@ -2614,7 +2617,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { 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); } diff --git a/src/librustc_typeck/collect/type_of.rs b/src/librustc_typeck/collect/type_of.rs index 8c9cd50a17d..17444c6d0ac 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/src/librustc_typeck/collect/type_of.rs @@ -326,21 +326,39 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { 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() diff --git a/src/librustc_typeck/lib.rs b/src/librustc_typeck/lib.rs index 9ba2545ba63..a8247e2f494 100644 --- a/src/librustc_typeck/lib.rs +++ b/src/librustc_typeck/lib.rs @@ -100,7 +100,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::util; use rustc_session::config::EntryFnType; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::{symbol::sym, Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::{ @@ -194,6 +194,23 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) { .emit(); error = true; } + + for attr in it.attrs { + if tcx.sess.check_name(attr, sym::track_caller) { + tcx.sess + .struct_span_err( + attr.span, + "`main` function is not allowed to be `#[track_caller]`", + ) + .span_label( + main_span, + "`main` function is not allowed to be `#[track_caller]`", + ) + .emit(); + error = true; + } + } + if error { return; } @@ -268,12 +285,29 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) { tcx.sess, span, E0752, - "start is not allowed to be `async`" + "`start` is not allowed to be `async`" ) - .span_label(span, "start is not allowed to be `async`") + .span_label(span, "`start` is not allowed to be `async`") .emit(); error = true; } + + for attr in it.attrs { + if tcx.sess.check_name(attr, sym::track_caller) { + tcx.sess + .struct_span_err( + attr.span, + "`start` is not allowed to be `#[track_caller]`", + ) + .span_label( + start_span, + "`start` is not allowed to be `#[track_caller]`", + ) + .emit(); + error = true; + } + } + if error { return; } diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index afc7cb346eb..8a6fe620af7 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -583,7 +583,7 @@ fn total_fields_in_adt_variant( self.tcx() .sess .delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT"); - return Err(()); + Err(()) } } } @@ -596,7 +596,7 @@ fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult< ty::Tuple(substs) => Ok(substs.len()), _ => { self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple"); - return Err(()); + Err(()) } } } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 8d1193e7f82..b4ced412e5e 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -2,8 +2,8 @@ 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 { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 2a090d6efa5..7b1dd5b11ed 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1395,10 +1395,13 @@ fn clean(&self, cx: &DocContext<'_>) -> Type { _ => 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; } @@ -1957,21 +1960,17 @@ fn clean(&self, cx: &DocContext<'_>) -> GenericArgs { 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), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 1bea41b6585..50eca75d7ca 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -10,7 +10,7 @@ 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; @@ -506,10 +506,11 @@ pub fn from_ast(diagnostic: &::rustc_errors::Handler, attrs: &[ast::Attribute]) .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; @@ -749,6 +750,10 @@ pub fn get_ref<'a>(&'a self) -> &'a str { pub fn statik() -> Lifetime { Lifetime("'static".to_string()) } + + pub fn elided() -> Lifetime { + Lifetime("'_".to_string()) + } } #[derive(Clone, Debug)] diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 52c30668826..c22538f21f6 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -2,9 +2,9 @@ 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; @@ -121,7 +121,10 @@ pub fn external_generic_args( 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 @@ -607,6 +610,9 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { 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), diff --git a/src/librustdoc/docfs.rs b/src/librustdoc/docfs.rs index 4ce6bcbe274..8b52ce710a4 100644 --- a/src/librustdoc/docfs.rs +++ b/src/librustdoc/docfs.rs @@ -69,14 +69,14 @@ pub fn write(&self, path: P, contents: C) -> Result<(), E> 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(()) } } diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 01b25fd6be4..21e476cbe06 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,6 +1,6 @@ -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; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 4f08452767a..d5f7ddcbdfb 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -43,13 +43,13 @@ extern crate rustc_typeck; extern crate test as testing; #[macro_use] -extern crate tracing as log; +extern crate tracing; use std::default::Default; use std::env; -use std::panic; use std::process; +use rustc_errors::ErrorReported; use rustc_session::config::{make_crate_type_option, ErrorOutputType, RustcOptGroup}; use rustc_session::getopts; use rustc_session::{early_error, early_warn}; @@ -82,22 +82,14 @@ struct Output { } pub fn main() { - let thread_stack_size: usize = if cfg!(target_os = "haiku") { - 16_000_000 // 16MB on Haiku - } else { - 32_000_000 // 32MB on other platforms - }; rustc_driver::set_sigpipe_handler(); rustc_driver::install_ice_hook(); rustc_driver::init_env_logger("RUSTDOC_LOG"); - - let res = std::thread::Builder::new() - .stack_size(thread_stack_size) - .spawn(move || get_args().map(|args| main_args(&args)).unwrap_or(1)) - .unwrap() - .join() - .unwrap_or(rustc_driver::EXIT_FAILURE); - process::exit(res); + let exit_code = rustc_driver::catch_with_exit_code(|| match get_args() { + Some(args) => main_args(&args), + _ => Err(ErrorReported), + }); + process::exit(exit_code); } fn get_args() -> Option> { @@ -418,7 +410,10 @@ fn usage(argv0: &str) { println!("{}", options.usage(&format!("{} [options] ", argv0))); } -fn main_args(args: &[String]) -> i32 { +/// A result type used by several functions under `main()`. +type MainResult = Result<(), ErrorReported>; + +fn main_args(args: &[String]) -> MainResult { let mut options = getopts::Options::new(); for option in opts() { (option.apply)(&mut options); @@ -429,24 +424,27 @@ fn main_args(args: &[String]) -> i32 { early_error(ErrorOutputType::default(), &err.to_string()); } }; + + // Note that we discard any distinction between different non-zero exit + // codes from `from_matches` here. let options = match config::Options::from_matches(&matches) { Ok(opts) => opts, - Err(code) => return code, + Err(code) => return if code == 0 { Ok(()) } else { Err(ErrorReported) }, }; - rustc_interface::interface::setup_callbacks_and_run_in_default_thread_pool_with_globals( + rustc_interface::util::setup_callbacks_and_run_in_thread_pool_with_globals( options.edition, + 1, // this runs single-threaded, even in a parallel compiler + &None, move || main_options(options), ) } -fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> i32 { +fn wrap_return(diag: &rustc_errors::Handler, res: Result<(), String>) -> MainResult { match res { - Ok(()) => 0, + Ok(()) => Ok(()), Err(err) => { - if !err.is_empty() { - diag.struct_err(&err).emit(); - } - 1 + diag.struct_err(&err).emit(); + Err(ErrorReported) } } } @@ -457,9 +455,9 @@ fn run_renderer( render_info: config::RenderInfo, diag: &rustc_errors::Handler, edition: rustc_span::edition::Edition, -) -> i32 { +) -> MainResult { match formats::run_format::(krate, renderopts, render_info, &diag, edition) { - Ok(_) => rustc_driver::EXIT_SUCCESS, + Ok(_) => Ok(()), Err(e) => { let mut msg = diag.struct_err(&format!("couldn't generate documentation: {}", e.error)); let file = e.file.display().to_string(); @@ -468,17 +466,17 @@ fn run_renderer( } else { msg.note(&format!("failed to create or modify \"{}\"", file)).emit() } - rustc_driver::EXIT_FAILURE + Err(ErrorReported) } } } -fn main_options(options: config::Options) -> i32 { +fn main_options(options: config::Options) -> MainResult { let diag = core::new_handler(options.error_format, None, &options.debugging_options); match (options.should_test, options.markdown_input()) { (true, true) => return wrap_return(&diag, markdown::test(options)), - (true, false) => return wrap_return(&diag, test::run(options)), + (true, false) => return test::run(options), (false, true) => { return wrap_return( &diag, @@ -500,44 +498,37 @@ fn main_options(options: config::Options) -> i32 { // compiler all the way through the analysis passes. The rustdoc output is // then generated from the cleaned AST of the crate. This runs all the // plug/cleaning passes. - let result = rustc_driver::catch_fatal_errors(move || { - let crate_name = options.crate_name.clone(); - let crate_version = options.crate_version.clone(); - let output_format = options.output_format; - let (mut krate, renderinfo, renderopts) = core::run_core(options); + let crate_name = options.crate_name.clone(); + let crate_version = options.crate_version.clone(); + let output_format = options.output_format; + let (mut krate, renderinfo, renderopts) = core::run_core(options); - info!("finished with rustc"); + info!("finished with rustc"); - if let Some(name) = crate_name { - krate.name = name - } + if let Some(name) = crate_name { + krate.name = name + } - krate.version = crate_version; + krate.version = crate_version; - let out = Output { krate, renderinfo, renderopts }; + let out = Output { krate, renderinfo, renderopts }; - if show_coverage { - // if we ran coverage, bail early, we don't need to also generate docs at this point - // (also we didn't load in any of the useful passes) - return rustc_driver::EXIT_SUCCESS; - } + if show_coverage { + // if we ran coverage, bail early, we don't need to also generate docs at this point + // (also we didn't load in any of the useful passes) + return Ok(()); + } - let Output { krate, renderinfo, renderopts } = out; - info!("going to format"); - let (error_format, edition, debugging_options) = diag_opts; - let diag = core::new_handler(error_format, None, &debugging_options); - match output_format { - None | Some(config::OutputFormat::Html) => { - run_renderer::(krate, renderopts, renderinfo, &diag, edition) - } - Some(config::OutputFormat::Json) => { - run_renderer::(krate, renderopts, renderinfo, &diag, edition) - } + let Output { krate, renderinfo, renderopts } = out; + info!("going to format"); + let (error_format, edition, debugging_options) = diag_opts; + let diag = core::new_handler(error_format, None, &debugging_options); + match output_format { + None | Some(config::OutputFormat::Html) => { + run_renderer::(krate, renderopts, renderinfo, &diag, edition) + } + Some(config::OutputFormat::Json) => { + run_renderer::(krate, renderopts, renderinfo, &diag, edition) } - }); - - match result { - Ok(output) => output, - Err(_) => panic::resume_unwind(Box::new(rustc_errors::FatalErrorMarker)), } } diff --git a/src/librustdoc/passes/calculate_doc_coverage.rs b/src/librustdoc/passes/calculate_doc_coverage.rs index 98300385c8f..b722cfc8f75 100644 --- a/src/librustdoc/passes/calculate_doc_coverage.rs +++ b/src/librustdoc/passes/calculate_doc_coverage.rs @@ -4,7 +4,6 @@ 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; @@ -155,7 +154,10 @@ fn fold_item(&mut self, i: clean::Item) -> Option { 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() => { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index bf7a43236e0..f84486347af 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -17,6 +17,7 @@ use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; +use std::cell::Cell; use std::ops::Range; use crate::clean::*; @@ -62,11 +63,15 @@ struct LinkCollector<'a, 'tcx> { cx: &'a DocContext<'tcx>, // NOTE: this may not necessarily be a module in the current crate mod_ids: Vec, + /// 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>, } 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( @@ -174,7 +179,7 @@ fn macro_resolve(&self, path_str: &str, parent_id: Option) -> Option fn resolve( &self, path_str: &str, - disambiguator: Option<&str>, + disambiguator: Option, ns: Namespace, current_item: &Option, parent_id: Option, @@ -214,7 +219,7 @@ fn resolve( 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") { + if disambiguator == 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)); @@ -347,6 +352,10 @@ fn resolve( 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 { @@ -415,7 +424,8 @@ fn resolve( 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) @@ -574,46 +584,14 @@ fn fold_item(&mut self, mut item: Item) -> Option { }; 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(); @@ -646,7 +624,7 @@ fn fold_item(&mut self, mut item: Item) -> Option { } } - match kind { + match disambiguator.map(Disambiguator::ns) { Some(ns @ ValueNS) => { match self.resolve( path_str, @@ -789,6 +767,42 @@ fn fold_item(&mut self, mut item: Item) -> Option { } 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() @@ -837,6 +851,94 @@ fn fold_crate(&mut self, mut c: Crate) -> Crate { } } +#[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 diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 0fdeefd79e9..3000afde0c2 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -28,7 +28,7 @@ pub fn collect_trait_impls(krate: Crate, cx: &DocContext<'_>) -> Crate { let mut new_items = Vec::new(); for &cnum in cx.tcx.crates().iter() { - for &did in cx.tcx.all_trait_implementations(cnum).iter() { + for &(did, _) in cx.tcx.all_trait_implementations(cnum).iter() { inline::build_impl(cx, did, None, &mut new_items); } } diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index ba1341e652c..62f52ea5213 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -42,7 +42,7 @@ pub struct TestOptions { pub attrs: Vec, } -pub fn run(options: Options) -> Result<(), String> { +pub fn run(options: Options) -> Result<(), ErrorReported> { let input = config::Input::File(options.input.clone()); let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name; @@ -150,7 +150,7 @@ pub fn run(options: Options) -> Result<(), String> { }); let tests = match tests { Ok(tests) => tests, - Err(ErrorReported) => return Err(String::new()), + Err(ErrorReported) => return Err(ErrorReported), }; test_args.insert(0, "rustdoctest".to_string()); @@ -398,7 +398,7 @@ pub fn make_test( // 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; @@ -943,7 +943,12 @@ fn visit_testable( // 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, diff --git a/src/test/codegen-units/polymorphization/pr-75255.rs b/src/test/codegen-units/polymorphization/pr-75255.rs new file mode 100644 index 00000000000..af47b440640 --- /dev/null +++ b/src/test/codegen-units/polymorphization/pr-75255.rs @@ -0,0 +1,52 @@ +// 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() -> u64 { + 42 +} + +fn foo() { + let x = [1, 2, 3, std::mem::size_of::()]; + x.iter().map(|_| ()); +} + +//~ MONO_ITEM fn core::iter[0]::adapters[0]::{{impl}}[29]::new[0], pr_75255::foo[0]::{{closure}}[0]> @@ pr_75255-cgu.0[External] +//~ MONO_ITEM fn core::iter[0]::traits[0]::iterator[0]::Iterator[0]::map[0], (), pr_75255::foo[0]::{{closure}}[0]> @@ pr_75255-cgu.1[Internal] + +fn bar() { + std::iter::repeat(unused::); +} + +//~ MONO_ITEM fn core::iter[0]::sources[0]::repeat[0] u64> @@ pr_75255-cgu.1[Internal] + +pub fn dispatch() { + foo::(); + foo::>(); + + bar::(); + bar::>(); +} + +// These are all the items that aren't relevant to the test. +//~ MONO_ITEM fn core::mem[0]::size_of[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::mem[0]::size_of[0]> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::mem[0]::size_of[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::add[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::is_null[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::offset[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_add[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::const_ptr[0]::{{impl}}[0]::wrapping_offset[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::non_null[0]::{{impl}}[3]::new_unchecked[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::ptr[0]::null[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::as_ptr[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::iter[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn core::slice[0]::{{impl}}[0]::len[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::dispatch[0] @@ pr_75255-cgu.1[External] +//~ MONO_ITEM fn pr_75255::foo[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::foo[0]> @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::bar[0] @@ pr_75255-cgu.1[Internal] +//~ MONO_ITEM fn pr_75255::bar[0]> @@ pr_75255-cgu.1[Internal] diff --git a/src/test/codegen/some-global-nonnull.rs b/src/test/codegen/some-global-nonnull.rs new file mode 100644 index 00000000000..59c47de4129 --- /dev/null +++ b/src/test/codegen/some-global-nonnull.rs @@ -0,0 +1,25 @@ +// 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) { + if let Some(f) = f_maybe { + f(); + } +} + +fn inner0() { + unsafe { ext_fn0() }; +} + +extern "C" { + fn ext_fn0(); +} diff --git a/src/test/debuginfo/function-arguments-naked.rs b/src/test/debuginfo/function-arguments-naked.rs index e88a99b322e..5f3a1eb44e4 100644 --- a/src/test/debuginfo/function-arguments-naked.rs +++ b/src/test/debuginfo/function-arguments-naked.rs @@ -3,6 +3,9 @@ // 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 @@ -24,6 +27,7 @@ // lldb-command:continue +#![feature(asm)] #![feature(naked_functions)] #![feature(omit_gdb_pretty_printer_section)] #![omit_gdb_pretty_printer_section] @@ -33,8 +37,6 @@ fn main() { } #[naked] -fn naked(x: usize, y: usize) { - zzz(); // #break +extern "C" fn naked(x: usize, y: usize) { + unsafe { asm!("ret"); } // #break } - -fn zzz() { () } diff --git a/src/test/debuginfo/pretty-std-collections-hash.rs b/src/test/debuginfo/pretty-std-collections-hash.rs index 361b300f28c..e8f52deabd8 100644 --- a/src/test/debuginfo/pretty-std-collections-hash.rs +++ b/src/test/debuginfo/pretty-std-collections-hash.rs @@ -9,35 +9,35 @@ // cdb-check:hash_set,d [...] : { size=15 } [Type: [...]::HashSet] // 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] diff --git a/src/test/mir-opt/const-promotion-extern-static.rs b/src/test/mir-opt/const-promotion-extern-static.rs index e63309a9bd2..9c30e040031 100644 --- a/src/test/mir-opt/const-promotion-extern-static.rs +++ b/src/test/mir-opt/const-promotion-extern-static.rs @@ -1,7 +1,7 @@ +// ignore-endian-big extern "C" { static X: i32; } - static Y: i32 = 42; // EMIT_MIR const_promotion_extern_static.BAR.PromoteTemps.diff diff --git a/src/test/mir-opt/const_allocation.rs b/src/test/mir-opt/const_allocation.rs index bb1c48e8e3c..b0fcb86fcee 100644 --- a/src/test/mir-opt/const_allocation.rs +++ b/src/test/mir-opt/const_allocation.rs @@ -1,5 +1,5 @@ +// ignore-endian-big // EMIT_MIR_FOR_EACH_BIT_WIDTH - static FOO: &[(Option, &[&str])] = &[(None, &[]), (None, &["foo", "bar"]), (Some(42), &["meh", "mop", "möp"])]; diff --git a/src/test/mir-opt/const_allocation2.rs b/src/test/mir-opt/const_allocation2.rs index 56839255c0e..30afedffb39 100644 --- a/src/test/mir-opt/const_allocation2.rs +++ b/src/test/mir-opt/const_allocation2.rs @@ -1,5 +1,5 @@ +// ignore-endian-big // EMIT_MIR_FOR_EACH_BIT_WIDTH - // EMIT_MIR const_allocation2.main.ConstProp.after.mir fn main() { FOO; diff --git a/src/test/mir-opt/const_allocation3.rs b/src/test/mir-opt/const_allocation3.rs index 2ce289aea3f..ddeb32ab9a5 100644 --- a/src/test/mir-opt/const_allocation3.rs +++ b/src/test/mir-opt/const_allocation3.rs @@ -1,5 +1,5 @@ +// ignore-endian-big // EMIT_MIR_FOR_EACH_BIT_WIDTH - // EMIT_MIR const_allocation3.main.ConstProp.after.mir fn main() { FOO; diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit new file mode 100644 index 00000000000..721766f9849 --- /dev/null +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit @@ -0,0 +1,85 @@ +- // 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()) + // mir::Constant + // + span: $DIR/large_array_index.rs:4:11: 7:2 + // + literal: Const { ty: (), val: Value(Scalar()) } + 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 + } + } + diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit new file mode 100644 index 00000000000..eae2ce6671c --- /dev/null +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit @@ -0,0 +1,85 @@ +- // 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()) + // mir::Constant + // + span: $DIR/large_array_index.rs:4:11: 7:2 + // + literal: Const { ty: (), val: Value(Scalar()) } + 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 + } + } + diff --git a/src/test/mir-opt/const_prop/large_array_index.rs b/src/test/mir-opt/const_prop/large_array_index.rs new file mode 100644 index 00000000000..48d134376db --- /dev/null +++ b/src/test/mir-opt/const_prop/large_array_index.rs @@ -0,0 +1,7 @@ +// 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]; +} diff --git a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff index e78bc31b774..6e2ee0957ab 100644 --- a/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/mutable_variable_aggregate_mut_ref.main.ConstProp.diff @@ -23,15 +23,13 @@ // + 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 diff --git a/src/test/mir-opt/inline/inline-into-box-place.rs b/src/test/mir-opt/inline/inline-into-box-place.rs index 30c9a5d6b8f..57298605b18 100644 --- a/src/test/mir-opt/inline/inline-into-box-place.rs +++ b/src/test/mir-opt/inline/inline-into-box-place.rs @@ -1,8 +1,8 @@ +// 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> = box Vec::new(); diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index 96df5c6a518..9ca6f93c9bc 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -2,58 +2,76 @@ + // MIR for `bar` after InstrumentCoverage fn bar() -> bool { - let mut _0: bool; // return place in scope 0 at $DIR/instrument_coverage.rs:18:13: 18:17 -+ let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18 + let mut _0: bool; // return place in scope 0 at /the/src/instrument_coverage.rs:19:13: 19:17 ++ let mut _1: (); // in scope 0 at /the/src/instrument_coverage.rs:19:18: 19:18 bb0: { -+ StorageLive(_1); // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18 -+ _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const 529_u32, const 541_u32) -> bb2; // scope 0 at $DIR/instrument_coverage.rs:18:18: 18:18 ++ StorageLive(_1); // scope 0 at /the/src/instrument_coverage.rs:19:18: 19:18 ++ _1 = const std::intrinsics::count_code_region(const 10208505205182607101_u64, const 0_u32, const "/the/src/instrument_coverage.rs", const 19_u32, const 18_u32, const 21_u32, const 2_u32) -> bb2; // scope 0 at /the/src/instrument_coverage.rs:19:18: 19:18 + // ty::Const -+ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region} ++ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region} + // + val: Value(Scalar()) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 -+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar()) } ++ // + span: /the/src/instrument_coverage.rs:19:18: 19:18 ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar()) } + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0x8dabe565aaa2aefd)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 ++ // + span: /the/src/instrument_coverage.rs:19:18: 19:18 + // + literal: Const { ty: u64, val: Value(Scalar(0x8dabe565aaa2aefd)) } + // ty::Const + // + ty: u32 + // + val: Value(Scalar(0x00000000)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 ++ // + span: /the/src/instrument_coverage.rs:19:18: 19:18 + // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) } + // ty::Const ++ // + ty: &str ++ // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 }) ++ // mir::Constant ++ // + span: /the/src/instrument_coverage.rs:19:18: 19:18 ++ // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 }) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000013)) ++ // mir::Constant ++ // + span: /the/src/instrument_coverage.rs:19:18: 19:18 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000013)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x00000012)) ++ // mir::Constant ++ // + span: /the/src/instrument_coverage.rs:19:18: 19:18 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000012)) } ++ // ty::Const + // + ty: u32 -+ // + val: Value(Scalar(0x00000211)) ++ // + val: Value(Scalar(0x00000015)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 -+ // + literal: Const { ty: u32, val: Value(Scalar(0x00000211)) } ++ // + span: /the/src/instrument_coverage.rs:19:18: 19:18 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000015)) } + // ty::Const + // + ty: u32 -+ // + val: Value(Scalar(0x0000021d)) ++ // + val: Value(Scalar(0x00000002)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:18:18: 18:18 -+ // + literal: Const { ty: u32, val: Value(Scalar(0x0000021d)) } ++ // + span: /the/src/instrument_coverage.rs:19:18: 19:18 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) } + } + + bb1 (cleanup): { -+ resume; // scope 0 at $DIR/instrument_coverage.rs:18:1: 20:2 ++ resume; // scope 0 at /the/src/instrument_coverage.rs:19:1: 21:2 + } + + bb2: { -+ StorageDead(_1); // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9 - _0 = const true; // scope 0 at $DIR/instrument_coverage.rs:19:5: 19:9 ++ StorageDead(_1); // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 + _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 // ty::Const // + ty: bool // + val: Value(Scalar(0x01)) // mir::Constant - // + span: $DIR/instrument_coverage.rs:19:5: 19:9 + // + span: /the/src/instrument_coverage.rs:20:5: 20:9 // + literal: Const { ty: bool, val: Value(Scalar(0x01)) } - return; // scope 0 at $DIR/instrument_coverage.rs:20:2: 20:2 + return; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 1bcc98de8d4..3f47aa13bf9 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -2,99 +2,117 @@ + // MIR for `main` after InstrumentCoverage fn main() -> () { - let mut _0: (); // return place in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11 - let mut _1: (); // in scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 - let mut _2: bool; // in scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 - let mut _3: !; // in scope 0 at $DIR/instrument_coverage.rs:11:18: 13:10 -+ let mut _4: (); // in scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11 + let mut _0: (); // return place in scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11 + let mut _1: (); // in scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2 + let mut _2: bool; // in scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 + let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10 ++ let mut _4: (); // in scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11 bb0: { -- falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 -+ StorageLive(_4); // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11 -+ _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const 425_u32, const 493_u32) -> bb7; // scope 0 at $DIR/instrument_coverage.rs:9:11: 9:11 +- falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 ++ StorageLive(_4); // scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11 ++ _4 = const std::intrinsics::count_code_region(const 16004455475339839479_u64, const 0_u32, const "/the/src/instrument_coverage.rs", const 10_u32, const 11_u32, const 16_u32, const 2_u32) -> bb7; // scope 0 at /the/src/instrument_coverage.rs:10:11: 10:11 + // ty::Const -+ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region} ++ // + ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region} + // + val: Value(Scalar()) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 -+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar()) } ++ // + span: /the/src/instrument_coverage.rs:10:11: 10:11 ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u64, u32, &'static str, u32, u32, u32, u32) {std::intrinsics::count_code_region}, val: Value(Scalar()) } + // ty::Const + // + ty: u64 + // + val: Value(Scalar(0xde1b3f75a72fc7f7)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 ++ // + span: /the/src/instrument_coverage.rs:10:11: 10:11 + // + literal: Const { ty: u64, val: Value(Scalar(0xde1b3f75a72fc7f7)) } + // ty::Const + // + ty: u32 + // + val: Value(Scalar(0x00000000)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 ++ // + span: /the/src/instrument_coverage.rs:10:11: 10:11 + // + literal: Const { ty: u32, val: Value(Scalar(0x00000000)) } + // ty::Const ++ // + ty: &str ++ // + val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 }) ++ // mir::Constant ++ // + span: /the/src/instrument_coverage.rs:10:11: 10:11 ++ // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [47, 116, 104, 101, 47, 115, 114, 99, 47, 105, 110, 115, 116, 114, 117, 109, 101, 110, 116, 95, 99, 111, 118, 101, 114, 97, 103, 101, 46, 114, 115], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [2147483647], len: Size { raw: 31 } }, size: Size { raw: 31 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 31 }) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x0000000a)) ++ // mir::Constant ++ // + span: /the/src/instrument_coverage.rs:10:11: 10:11 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x0000000a)) } ++ // ty::Const ++ // + ty: u32 ++ // + val: Value(Scalar(0x0000000b)) ++ // mir::Constant ++ // + span: /the/src/instrument_coverage.rs:10:11: 10:11 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x0000000b)) } ++ // ty::Const + // + ty: u32 -+ // + val: Value(Scalar(0x000001a9)) ++ // + val: Value(Scalar(0x00000010)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 -+ // + literal: Const { ty: u32, val: Value(Scalar(0x000001a9)) } ++ // + span: /the/src/instrument_coverage.rs:10:11: 10:11 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000010)) } + // ty::Const + // + ty: u32 -+ // + val: Value(Scalar(0x000001ed)) ++ // + val: Value(Scalar(0x00000002)) + // mir::Constant -+ // + span: $DIR/instrument_coverage.rs:9:11: 9:11 -+ // + literal: Const { ty: u32, val: Value(Scalar(0x000001ed)) } ++ // + span: /the/src/instrument_coverage.rs:10:11: 10:11 ++ // + literal: Const { ty: u32, val: Value(Scalar(0x00000002)) } } bb1: { - StorageLive(_2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 - _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 + StorageLive(_2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 + _2 = const bar() -> [return: bb3, unwind: bb2]; // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 // ty::Const // + ty: fn() -> bool {bar} // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/instrument_coverage.rs:11:12: 11:15 + // + span: /the/src/instrument_coverage.rs:12:12: 12:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value(Scalar()) } } bb2 (cleanup): { - resume; // scope 0 at $DIR/instrument_coverage.rs:9:1: 15:2 + resume; // scope 0 at /the/src/instrument_coverage.rs:10:1: 16:2 } bb3: { - FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/instrument_coverage.rs:11:12: 11:17 - switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10 + FakeRead(ForMatchedPlace, _2); // scope 0 at /the/src/instrument_coverage.rs:12:12: 12:17 + switchInt(_2) -> [false: bb5, otherwise: bb4]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 } bb4: { - falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10 + falseEdge -> [real: bb6, imaginary: bb5]; // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 } bb5: { - _1 = const (); // scope 0 at $DIR/instrument_coverage.rs:11:9: 13:10 + _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:12:9: 14:10 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/instrument_coverage.rs:11:9: 13:10 + // + span: /the/src/instrument_coverage.rs:12:9: 14:10 // + literal: Const { ty: (), val: Value(Scalar()) } - StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6 - goto -> bb0; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 + StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6 + goto -> bb0; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } bb6: { - _0 = const (); // scope 0 at $DIR/instrument_coverage.rs:12:13: 12:18 + _0 = const (); // scope 0 at /the/src/instrument_coverage.rs:13:13: 13:18 // ty::Const // + ty: () // + val: Value(Scalar()) // mir::Constant - // + span: $DIR/instrument_coverage.rs:12:13: 12:18 + // + span: /the/src/instrument_coverage.rs:13:13: 13:18 // + literal: Const { ty: (), val: Value(Scalar()) } - StorageDead(_2); // scope 0 at $DIR/instrument_coverage.rs:14:5: 14:6 - return; // scope 0 at $DIR/instrument_coverage.rs:15:2: 15:2 + StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:15:5: 15:6 + return; // scope 0 at /the/src/instrument_coverage.rs:16:2: 16:2 + } + + bb7: { -+ StorageDead(_4); // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 -+ falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at $DIR/instrument_coverage.rs:10:5: 14:6 ++ StorageDead(_4); // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 ++ falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } } diff --git a/src/test/mir-opt/instrument_coverage.rs b/src/test/mir-opt/instrument_coverage.rs index 4770ec9b66e..430573c7c05 100644 --- a/src/test/mir-opt/instrument_coverage.rs +++ b/src/test/mir-opt/instrument_coverage.rs @@ -3,7 +3,8 @@ // intrinsics, during codegen. // needs-profiler-support -// compile-flags: -Zinstrument-coverage +// ignore-windows +// compile-flags: -Zinstrument-coverage --remap-path-prefix={{src-base}}=/the/src // EMIT_MIR instrument_coverage.main.InstrumentCoverage.diff // EMIT_MIR instrument_coverage.bar.InstrumentCoverage.diff fn main() { @@ -18,3 +19,18 @@ fn main() { fn bar() -> bool { true } + +// Note that the MIR with injected coverage intrinsics includes references to source locations, +// including the source file absolute path. Typically, MIR pretty print output with file +// references are safe because the file prefixes are substituted with `$DIR`, but in this case +// the file references are encoded as function arguments, with an `Operand` type representation +// (`Slice` `Allocation` interned byte array) that cannot be normalized by simple substitution. +// +// The first workaround is to use the `SourceMap`-supported `--remap-path-prefix` option; however, +// the implementation of the `--remap-path-prefix` option currently joins the new prefix and the +// remaining source path with an OS-specific path separator (`\` on Windows). This difference still +// shows up in the byte array representation of the path, causing Windows tests to fail to match +// blessed results baselined with a `/` path separator. +// +// Since this `mir-opt` test does not have any significant platform dependencies, other than the +// path separator differences, the final workaround is to disable testing on Windows. diff --git a/src/test/rustdoc-ui/auxiliary/extern_macros.rs b/src/test/rustdoc-ui/auxiliary/extern_macros.rs new file mode 100644 index 00000000000..ee1fec4c5c2 --- /dev/null +++ b/src/test/rustdoc-ui/auxiliary/extern_macros.rs @@ -0,0 +1,7 @@ +#[macro_export] +macro_rules! attrs_on_struct { + ( $( #[$attr:meta] )* ) => { + $( #[$attr] )* + pub struct ExpandedStruct; + } +} diff --git a/src/test/rustdoc-ui/doctest-output.rs b/src/test/rustdoc-ui/doctest-output.rs index f812263c252..e0e1e061ac7 100644 --- a/src/test/rustdoc-ui/doctest-output.rs +++ b/src/test/rustdoc-ui/doctest-output.rs @@ -1,3 +1,5 @@ +// 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 @@ -6,6 +8,10 @@ //! assert_eq!(1 + 1, 2); //! ``` +extern crate extern_macros as macros; + +use macros::attrs_on_struct; + pub mod foo { /// ``` @@ -13,3 +19,9 @@ pub mod foo { /// ``` pub fn bar() {} } + +attrs_on_struct! { + /// ``` + /// assert!(true); + /// ``` +} diff --git a/src/test/rustdoc-ui/doctest-output.stdout b/src/test/rustdoc-ui/doctest-output.stdout index 9a55bf50196..c72bd91d1dd 100644 --- a/src/test/rustdoc-ui/doctest-output.stdout +++ b/src/test/rustdoc-ui/doctest-output.stdout @@ -1,7 +1,8 @@ -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 diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs new file mode 100644 index 00000000000..1a7a2fce7a3 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs @@ -0,0 +1,68 @@ +#![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() {} diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr new file mode 100644 index 00000000000..9edf838f9d8 --- /dev/null +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr @@ -0,0 +1,95 @@ +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 + diff --git a/src/test/rustdoc/auxiliary/elided-lifetime.rs b/src/test/rustdoc/auxiliary/elided-lifetime.rs new file mode 100644 index 00000000000..4f2c93379d8 --- /dev/null +++ b/src/test/rustdoc/auxiliary/elided-lifetime.rs @@ -0,0 +1,11 @@ +#![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) +} diff --git a/src/test/rustdoc/elided-lifetime.rs b/src/test/rustdoc/elided-lifetime.rs new file mode 100644 index 00000000000..5a32554f972 --- /dev/null +++ b/src/test/rustdoc/elided-lifetime.rs @@ -0,0 +1,43 @@ +// 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<'_>" +pub fn test1(a: &u32) -> Ref { + Ref(a) +} + +// @has foo/fn.test2.html +// @matches - "Ref<'_>" +pub fn test2(a: &u32) -> Ref<'_> { + Ref(a) +} + +// @has foo/fn.test3.html +// @matches - "Ref<'_>" +pub fn test3(a: &u32) -> ARef { + Ref(a) +} + +// @has foo/fn.test4.html +// @matches - "Ref<'_>" +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<'_>" +// @has foo/bar/fn.test6.html +// @matches - "Ref<'_>" +#[doc(inline)] +pub extern crate bar; diff --git a/src/test/rustdoc/intra-link-trait-item.rs b/src/test/rustdoc/intra-link-trait-item.rs new file mode 100644 index 00000000000..54270414c9d --- /dev/null +++ b/src/test/rustdoc/intra-link-trait-item.rs @@ -0,0 +1,12 @@ +// 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() {} +} diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs index bfb4da4c8f5..736a8633dac 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate-rpass.rs @@ -29,7 +29,7 @@ fn name(&self) -> &'static str { 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() diff --git a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs index e6a6f73bd47..bd477b793fc 100644 --- a/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs +++ b/src/test/ui-fulldeps/auxiliary/lint-for-crate.rs @@ -27,7 +27,7 @@ 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) diff --git a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs index 836cb07d5d1..448c57da754 100644 --- a/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs +++ b/src/test/ui-fulldeps/mod_dir_path_canonicalized.rs @@ -19,7 +19,7 @@ mod gravy; pub fn main() { - rustc_ast::with_default_session_globals(|| parse()); + rustc_span::with_default_session_globals(|| parse()); assert_eq!(gravy::foo(), 10); } diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 8286b7fdb66..f0e3ab308e9 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -208,7 +208,7 @@ fn visit_expr(&mut self, e: &mut P) { } fn main() { - rustc_ast::with_default_session_globals(|| run()); + rustc_span::with_default_session_globals(|| run()); } fn run() { diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index 184e4706a4c..a6c2317c736 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -4,10 +4,11 @@ // no-prefer-dynamic #![feature(allocator_api)] +#![feature(slice_ptr_get)] extern crate helper; -use std::alloc::{self, AllocInit, AllocRef, Global, Layout, System}; +use std::alloc::{self, AllocRef, Global, Layout, System}; use std::sync::atomic::{AtomicUsize, Ordering}; static HITS: AtomicUsize = AtomicUsize::new(0); @@ -37,10 +38,10 @@ fn main() { unsafe { let layout = Layout::from_size_align(4, 2).unwrap(); - let memory = Global.alloc(layout.clone(), AllocInit::Uninitialized).unwrap(); - helper::work_with(&memory.ptr); + let memory = Global.alloc(layout.clone()).unwrap(); + helper::work_with(&memory); assert_eq!(HITS.load(Ordering::SeqCst), n + 1); - Global.dealloc(memory.ptr, layout); + Global.dealloc(memory.as_non_null_ptr(), layout); assert_eq!(HITS.load(Ordering::SeqCst), n + 2); let s = String::with_capacity(10); @@ -49,10 +50,10 @@ fn main() { drop(s); assert_eq!(HITS.load(Ordering::SeqCst), n + 4); - let memory = System.alloc(layout.clone(), AllocInit::Uninitialized).unwrap(); + let memory = System.alloc(layout.clone()).unwrap(); assert_eq!(HITS.load(Ordering::SeqCst), n + 4); - helper::work_with(&memory.ptr); - System.dealloc(memory.ptr, layout); + helper::work_with(&memory); + System.dealloc(memory.as_non_null_ptr(), layout); assert_eq!(HITS.load(Ordering::SeqCst), n + 4); } } diff --git a/src/test/ui/allocator/xcrate-use.rs b/src/test/ui/allocator/xcrate-use.rs index 7de1ab7a553..a1446b3664d 100644 --- a/src/test/ui/allocator/xcrate-use.rs +++ b/src/test/ui/allocator/xcrate-use.rs @@ -5,11 +5,12 @@ // no-prefer-dynamic #![feature(allocator_api)] +#![feature(slice_ptr_get)] extern crate custom; extern crate helper; -use std::alloc::{AllocInit, AllocRef, Global, Layout, System}; +use std::alloc::{AllocRef, Global, Layout, System}; use std::sync::atomic::{AtomicUsize, Ordering}; #[global_allocator] @@ -20,16 +21,16 @@ fn main() { let n = GLOBAL.0.load(Ordering::SeqCst); let layout = Layout::from_size_align(4, 2).unwrap(); - let memory = Global.alloc(layout.clone(), AllocInit::Uninitialized).unwrap(); - helper::work_with(&memory.ptr); + let memory = Global.alloc(layout.clone()).unwrap(); + helper::work_with(&memory); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 1); - Global.dealloc(memory.ptr, layout); + Global.dealloc(memory.as_non_null_ptr(), layout); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); - let memory = System.alloc(layout.clone(), AllocInit::Uninitialized).unwrap(); + let memory = System.alloc(layout.clone()).unwrap(); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); - helper::work_with(&memory.ptr); - System.dealloc(memory.ptr, layout); + helper::work_with(&memory); + System.dealloc(memory.as_non_null_ptr(), layout); assert_eq!(GLOBAL.0.load(Ordering::SeqCst), n + 2); } } diff --git a/src/test/ui/asm/bad-arch.rs b/src/test/ui/asm/bad-arch.rs new file mode 100644 index 00000000000..1d21ae8df24 --- /dev/null +++ b/src/test/ui/asm/bad-arch.rs @@ -0,0 +1,19 @@ +// 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 + } +} diff --git a/src/test/ui/asm/bad-arch.stderr b/src/test/ui/asm/bad-arch.stderr new file mode 100644 index 00000000000..cb876f28650 --- /dev/null +++ b/src/test/ui/asm/bad-arch.stderr @@ -0,0 +1,8 @@ +error[E0472]: asm! is unsupported on this target + --> $DIR/bad-arch.rs:16:9 + | +LL | asm!(""); + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/async-await/issue-68523-start.rs b/src/test/ui/async-await/issue-68523-start.rs index 5988dffd68f..2ced88a16cc 100644 --- a/src/test/ui/async-await/issue-68523-start.rs +++ b/src/test/ui/async-await/issue-68523-start.rs @@ -4,6 +4,6 @@ #[start] pub async fn start(_: isize, _: *const *const u8) -> isize { -//~^ ERROR start is not allowed to be `async` +//~^ ERROR `start` is not allowed to be `async` 0 } diff --git a/src/test/ui/async-await/issue-68523-start.stderr b/src/test/ui/async-await/issue-68523-start.stderr index e471945900e..3a0a3b5dece 100644 --- a/src/test/ui/async-await/issue-68523-start.stderr +++ b/src/test/ui/async-await/issue-68523-start.stderr @@ -1,8 +1,8 @@ -error[E0752]: start is not allowed to be `async` +error[E0752]: `start` is not allowed to be `async` --> $DIR/issue-68523-start.rs:6:1 | LL | pub async fn start(_: isize, _: *const *const u8) -> isize { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ start is not allowed to be `async` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `start` is not allowed to be `async` error: aborting due to previous error diff --git a/src/test/ui/btreemap/btreemap_into_iterator_lifetime.rs b/src/test/ui/btreemap/btreemap_into_iterator_lifetime.rs new file mode 100644 index 00000000000..fda825bc65e --- /dev/null +++ b/src/test/ui/btreemap/btreemap_into_iterator_lifetime.rs @@ -0,0 +1,23 @@ +// check-pass + +use std::collections::{BTreeMap, HashMap}; + +trait Map +where + for<'a> &'a Self: IntoIterator, +{ + type Key; + type Value; +} + +impl Map for HashMap { + type Key = K; + type Value = V; +} + +impl Map for BTreeMap { + type Key = K; + type Value = V; +} + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-in-trait-ungated.stderr b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr index bdae6bc362c..d53a4ac2d4c 100644 --- a/src/test/ui/const-generics/const-param-in-trait-ungated.stderr +++ b/src/test/ui/const-generics/const-param-in-trait-ungated.stderr @@ -4,8 +4,8 @@ error[E0658]: const generics are unstable LL | trait Trait {} | ^ | - = note: see issue #44580 for more information - = help: add `#![feature(const_generics)]` to the crate attributes to enable + = note: see issue #74878 for more information + = help: add `#![feature(min_const_generics)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr index 616f0fa8f1a..5d379ff083c 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -10,8 +10,8 @@ error[E0658]: const generics are unstable LL | struct B(PhantomData<[T; N]>); | ^ | - = note: see issue #44580 for more information - = help: add `#![feature(const_generics)]` to the crate attributes to enable + = note: see issue #74878 for more information + = help: add `#![feature(min_const_generics)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/defaults/wrong-order.full.stderr b/src/test/ui/const-generics/defaults/wrong-order.full.stderr new file mode 100644 index 00000000000..c51028d5b20 --- /dev/null +++ b/src/test/ui/const-generics/defaults/wrong-order.full.stderr @@ -0,0 +1,19 @@ +error: type parameters with a default must be trailing + --> $DIR/wrong-order.rs:5:10 + | +LL | struct A { + | ^ + | + = 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 for more information + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/const-generics/defaults/wrong-order.min.stderr b/src/test/ui/const-generics/defaults/wrong-order.min.stderr new file mode 100644 index 00000000000..29a46367004 --- /dev/null +++ b/src/test/ui/const-generics/defaults/wrong-order.min.stderr @@ -0,0 +1,10 @@ +error: type parameters with a default must be trailing + --> $DIR/wrong-order.rs:5:10 + | +LL | struct A { + | ^ + | + = note: using type defaults and const parameters in the same parameter list is currently not permitted + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/wrong-order.rs b/src/test/ui/const-generics/defaults/wrong-order.rs index 7f17c6358b7..cb36d456f38 100644 --- a/src/test/ui/const-generics/defaults/wrong-order.rs +++ b/src/test/ui/const-generics/defaults/wrong-order.rs @@ -1,4 +1,6 @@ -#![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 { //~^ ERROR type parameters with a default must be trailing diff --git a/src/test/ui/const-generics/defaults/wrong-order.stderr b/src/test/ui/const-generics/defaults/wrong-order.stderr deleted file mode 100644 index 283f6656121..00000000000 --- a/src/test/ui/const-generics/defaults/wrong-order.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error: type parameters with a default must be trailing - --> $DIR/wrong-order.rs:3:10 - | -LL | struct A { - | ^ - | - = 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 for more information - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-56445.full.stderr b/src/test/ui/const-generics/issues/issue-56445.full.stderr new file mode 100644 index 00000000000..d853ec5015e --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-56445.full.stderr @@ -0,0 +1,20 @@ +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 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 + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0771`. diff --git a/src/test/ui/const-generics/issues/issue-56445.min.stderr b/src/test/ui/const-generics/issues/issue-56445.min.stderr new file mode 100644 index 00000000000..ca35ee5b290 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-56445.min.stderr @@ -0,0 +1,20 @@ +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 + +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`. diff --git a/src/test/ui/const-generics/issues/issue-56445.rs b/src/test/ui/const-generics/issues/issue-56445.rs index 26441512e3f..174eb16abfc 100644 --- a/src/test/ui/const-generics/issues/issue-56445.rs +++ b/src/test/ui/const-generics/issues/issue-56445.rs @@ -1,12 +1,13 @@ // 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<'_, ""> {} diff --git a/src/test/ui/const-generics/issues/issue-56445.stderr b/src/test/ui/const-generics/issues/issue-56445.stderr deleted file mode 100644 index fba638b0b2b..00000000000 --- a/src/test/ui/const-generics/issues/issue-56445.stderr +++ /dev/null @@ -1,20 +0,0 @@ -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 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 - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0771`. diff --git a/src/test/ui/const-generics/issues/issue-60263.stderr b/src/test/ui/const-generics/issues/issue-60263.stderr index 7b50c442d2f..aeef296f385 100644 --- a/src/test/ui/const-generics/issues/issue-60263.stderr +++ b/src/test/ui/const-generics/issues/issue-60263.stderr @@ -4,8 +4,8 @@ error[E0658]: const generics are unstable LL | struct B; | ^ | - = note: see issue #44580 for more information - = help: add `#![feature(const_generics)]` to the crate attributes to enable + = note: see issue #74878 for more information + = help: add `#![feature(min_const_generics)]` to the crate attributes to enable error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr new file mode 100644 index 00000000000..c03b7252a3c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.full.stderr @@ -0,0 +1,11 @@ +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 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs index 26d74ffb254..ae2b0520fb1 100644 --- a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs +++ b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.rs @@ -1,7 +1,7 @@ // 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; diff --git a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr b/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr deleted file mode 100644 index 94a2b673a51..00000000000 --- a/src/test/ui/const-generics/issues/issue-60818-struct-constructors.stderr +++ /dev/null @@ -1,11 +0,0 @@ -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 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-61336-1.full.stderr b/src/test/ui/const-generics/issues/issue-61336-1.full.stderr new file mode 100644 index 00000000000..f18728eabbb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61336-1.full.stderr @@ -0,0 +1,11 @@ +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 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-61336-1.rs b/src/test/ui/const-generics/issues/issue-61336-1.rs index 2135c868bbc..201c0d039d9 100644 --- a/src/test/ui/const-generics/issues/issue-61336-1.rs +++ b/src/test/ui/const-generics/issues/issue-61336-1.rs @@ -1,7 +1,7 @@ -#![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(x: T) -> [T; N] { [x; N] diff --git a/src/test/ui/const-generics/issues/issue-61336-1.stderr b/src/test/ui/const-generics/issues/issue-61336-1.stderr deleted file mode 100644 index b2c69d57c40..00000000000 --- a/src/test/ui/const-generics/issues/issue-61336-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -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 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr new file mode 100644 index 00000000000..d21cd9df054 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr @@ -0,0 +1,24 @@ +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 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(x: T) -> [T; N] { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-61336-2.min.stderr b/src/test/ui/const-generics/issues/issue-61336-2.min.stderr new file mode 100644 index 00000000000..29ab7b1305e --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61336-2.min.stderr @@ -0,0 +1,15 @@ +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(x: T) -> [T; N] { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-61336-2.rs b/src/test/ui/const-generics/issues/issue-61336-2.rs index 52969056f00..25b9271105e 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.rs +++ b/src/test/ui/const-generics/issues/issue-61336-2.rs @@ -1,5 +1,6 @@ -#![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(x: T) -> [T; N] { [x; { N }] diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr deleted file mode 100644 index 5f3395223f9..00000000000 --- a/src/test/ui/const-generics/issues/issue-61336-2.stderr +++ /dev/null @@ -1,24 +0,0 @@ -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 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(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-61336.full.stderr b/src/test/ui/const-generics/issues/issue-61336.full.stderr new file mode 100644 index 00000000000..d1b5d5eb941 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61336.full.stderr @@ -0,0 +1,24 @@ +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 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(x: T) -> [T; N] { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-61336.min.stderr b/src/test/ui/const-generics/issues/issue-61336.min.stderr new file mode 100644 index 00000000000..bced8bbd82f --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61336.min.stderr @@ -0,0 +1,15 @@ +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(x: T) -> [T; N] { + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-61336.rs b/src/test/ui/const-generics/issues/issue-61336.rs index eb0f3097627..fb55542a1c9 100644 --- a/src/test/ui/const-generics/issues/issue-61336.rs +++ b/src/test/ui/const-generics/issues/issue-61336.rs @@ -1,5 +1,6 @@ -#![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(x: T) -> [T; N] { [x; N] diff --git a/src/test/ui/const-generics/issues/issue-61422.full.stderr b/src/test/ui/const-generics/issues/issue-61422.full.stderr new file mode 100644 index 00000000000..ac6c378295d --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61422.full.stderr @@ -0,0 +1,11 @@ +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 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-61422.rs b/src/test/ui/const-generics/issues/issue-61422.rs index 7e7ef6867ed..649f8b4255b 100644 --- a/src/test/ui/const-generics/issues/issue-61422.rs +++ b/src/test/ui/const-generics/issues/issue-61422.rs @@ -1,7 +1,7 @@ // 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; diff --git a/src/test/ui/const-generics/issues/issue-61422.stderr b/src/test/ui/const-generics/issues/issue-61422.stderr deleted file mode 100644 index 69bbaada691..00000000000 --- a/src/test/ui/const-generics/issues/issue-61422.stderr +++ /dev/null @@ -1,11 +0,0 @@ -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 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-61432.full.stderr b/src/test/ui/const-generics/issues/issue-61432.full.stderr new file mode 100644 index 00000000000..82b36de45a2 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61432.full.stderr @@ -0,0 +1,11 @@ +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 for more information + +warning: 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-61432.rs b/src/test/ui/const-generics/issues/issue-61432.rs index 0440468e9e6..91a4794099c 100644 --- a/src/test/ui/const-generics/issues/issue-61432.rs +++ b/src/test/ui/const-generics/issues/issue-61432.rs @@ -1,7 +1,7 @@ // 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() { // works: diff --git a/src/test/ui/const-generics/issues/issue-61432.stderr b/src/test/ui/const-generics/issues/issue-61432.stderr deleted file mode 100644 index 1d547b1b6c9..00000000000 --- a/src/test/ui/const-generics/issues/issue-61432.stderr +++ /dev/null @@ -1,11 +0,0 @@ -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 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-61747.full.stderr b/src/test/ui/const-generics/issues/issue-61747.full.stderr new file mode 100644 index 00000000000..3ccce5675fc --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61747.full.stderr @@ -0,0 +1,19 @@ +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 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 + diff --git a/src/test/ui/const-generics/issues/issue-61747.min.stderr b/src/test/ui/const-generics/issues/issue-61747.min.stderr new file mode 100644 index 00000000000..2061b6c55bb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61747.min.stderr @@ -0,0 +1,10 @@ +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 + diff --git a/src/test/ui/const-generics/issues/issue-61747.rs b/src/test/ui/const-generics/issues/issue-61747.rs index cc671163e85..4e5cde17f39 100644 --- a/src/test/ui/const-generics/issues/issue-61747.rs +++ b/src/test/ui/const-generics/issues/issue-61747.rs @@ -1,11 +1,13 @@ -#![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; impl 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 } } diff --git a/src/test/ui/const-generics/issues/issue-61747.stderr b/src/test/ui/const-generics/issues/issue-61747.stderr deleted file mode 100644 index 2685d9fdf16..00000000000 --- a/src/test/ui/const-generics/issues/issue-61747.stderr +++ /dev/null @@ -1,19 +0,0 @@ -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 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 - diff --git a/src/test/ui/const-generics/issues/issue-64494.rs b/src/test/ui/const-generics/issues/issue-64494.rs new file mode 100644 index 00000000000..4c755530b99 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-64494.rs @@ -0,0 +1,19 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Foo { + const VAL: usize; +} + +trait MyTrait {} + +trait True {} +struct Is; +impl True for Is<{true}> {} + +impl MyTrait for T where Is<{T::VAL == 5}>: True {} +//~^ ERROR constant expression depends on a generic parameter +impl MyTrait for T where Is<{T::VAL == 6}>: True {} +//~^ ERROR constant expression depends on a generic parameter + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-64494.stderr b/src/test/ui/const-generics/issues/issue-64494.stderr new file mode 100644 index 00000000000..30dca169643 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-64494.stderr @@ -0,0 +1,18 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-64494.rs:14:53 + | +LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/issue-64494.rs:16:53 + | +LL | impl MyTrait for T where Is<{T::VAL == 6}>: True {} + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs new file mode 100644 index 00000000000..a368c226ec3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72787.rs @@ -0,0 +1,32 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +pub struct IsLessOrEqual; +pub struct Condition; +pub trait True {} + +impl True for IsLessOrEqual where + Condition<{ LHS <= RHS }>: True +//~^ Error constant expression depends on a generic parameter +{ +} +impl True for Condition {} + +struct S; +impl S +where + IsLessOrEqual: True, + IsLessOrEqual: True, + IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, +//~^ Error constant expression depends on a generic parameter +//~| Error constant expression depends on a generic parameter +//~| Error constant expression depends on a generic parameter +//~| Error constant expression depends on a generic parameter + // Condition<{ 8 - I <= 8 - J }>: True, +{ + fn print() { + println!("I {} J {}", I, J); + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-72787.stderr b/src/test/ui/const-generics/issues/issue-72787.stderr new file mode 100644 index 00000000000..ed892e46bbb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72787.stderr @@ -0,0 +1,42 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-72787.rs:9:32 + | +LL | Condition<{ LHS <= RHS }>: True + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/issue-72787.rs:20:42 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/issue-72787.rs:20:42 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/issue-72787.rs:20:42 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/issue-72787.rs:20:42 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/const-generics/min_const_generics/assoc_const.rs b/src/test/ui/const-generics/min_const_generics/assoc_const.rs new file mode 100644 index 00000000000..fa75613d9dd --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/assoc_const.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(min_const_generics)] + +struct Foo; + +impl Foo { + const VALUE: usize = N * 2; +} + +trait Bar { + const ASSOC: usize; +} + +impl Bar for Foo { + const ASSOC: usize = N * 3; +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.rs b/src/test/ui/const-generics/min_const_generics/complex-expression.rs new file mode 100644 index 00000000000..f9cb0d2829d --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.rs @@ -0,0 +1,29 @@ +#![feature(min_const_generics)] + +fn test() {} + +fn ok() -> [u8; M] { + [0; { M }] +} + +struct Break0([u8; { N + 1 }]); +//~^ ERROR generic parameters must not be used inside of non trivial constant values + +struct Break1([u8; { { N } }]); +//~^ ERROR generic parameters must not be used inside of non trivial constant values + +fn break2() { + let _: [u8; N + 1]; + //~^ ERROR generic parameters must not be used inside of non trivial constant values +} + +fn break3() { + let _ = [0; N + 1]; + //~^ ERROR generic parameters must not be used inside of non trivial constant values +} + +trait Foo { + const ASSOC: usize; +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/complex-expression.stderr b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr new file mode 100644 index 00000000000..baed8d13f00 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/complex-expression.stderr @@ -0,0 +1,34 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/complex-expression.rs:9:38 + | +LL | struct Break0([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([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 + diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.rs b/src/test/ui/const-generics/min_const_generics/complex-types.rs new file mode 100644 index 00000000000..a396fa83aa6 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/complex-types.rs @@ -0,0 +1,18 @@ +#![feature(min_const_generics)] + +struct Foo; +//~^ ERROR using `[u8; 0]` as const generic parameters is forbidden + +struct Bar; +//~^ ERROR using `()` as const generic parameters is forbidden + +#[derive(PartialEq, Eq)] +struct No; + +struct Fez; +//~^ ERROR using `No` as const generic parameters is forbidden + +struct Faz; +//~^ ERROR using `&'static u8` as const generic parameters is forbidden + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/complex-types.stderr b/src/test/ui/const-generics/min_const_generics/complex-types.stderr new file mode 100644 index 00000000000..835b1f1a3e8 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/complex-types.stderr @@ -0,0 +1,38 @@ +error: using `[u8; 0]` as const generic parameters is forbidden + --> $DIR/complex-types.rs:3:21 + | +LL | struct Foo; + | ^^^^^^^ + | + = 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; + | ^^ + | + = 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; + | ^^ + | + = 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; + | ^^^^^^^^^^^ + | + = 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 + diff --git a/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs new file mode 100644 index 00000000000..423deae4600 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.rs @@ -0,0 +1,4 @@ +fn test() {} +//~^ ERROR const generics are unstable + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr new file mode 100644 index 00000000000..7f82a960da2 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/feature-gate-min_const_generics.stderr @@ -0,0 +1,12 @@ +error[E0658]: const generics are unstable + --> $DIR/feature-gate-min_const_generics.rs:1:15 + | +LL | fn test() {} + | ^ + | + = note: see issue #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`. diff --git a/src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs b/src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs index ae50252facd..3ccdd472613 100644 --- a/src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs +++ b/src/test/ui/const-generics/type-dependent/const-arg-in-const-arg.rs @@ -1,7 +1,8 @@ // 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; diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs new file mode 100644 index 00000000000..67d9f6baca5 --- /dev/null +++ b/src/test/ui/consts/unsizing-cast-non-null.rs @@ -0,0 +1,10 @@ +// Regression test for #75118. + +use std::ptr::NonNull; + +pub const fn dangling_slice() -> NonNull<[T]> { + NonNull::<[T; 0]>::dangling() + //~^ ERROR: unsizing casts are only allowed for references right now +} + +fn main() {} diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr new file mode 100644 index 00000000000..6575355daad --- /dev/null +++ b/src/test/ui/consts/unsizing-cast-non-null.stderr @@ -0,0 +1,12 @@ +error[E0723]: unsizing casts are only allowed for references right now + --> $DIR/unsizing-cast-non-null.rs:6:5 + | +LL | NonNull::<[T; 0]>::dangling() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/feature-gates/feature-gate-asm.rs b/src/test/ui/feature-gates/feature-gate-asm.rs index 753e924f004..59f04372fff 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.rs +++ b/src/test/ui/feature-gates/feature-gate-asm.rs @@ -1,4 +1,4 @@ -// ignore-emscripten +// only-x86_64 fn main() { unsafe { diff --git a/src/test/ui/feature-gates/feature-gate-asm2.rs b/src/test/ui/feature-gates/feature-gate-asm2.rs index e9349acb643..aa63aff1c5e 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.rs +++ b/src/test/ui/feature-gates/feature-gate-asm2.rs @@ -1,4 +1,4 @@ -// ignore-emscripten +// only-x86_64 fn main() { unsafe { diff --git a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr index b2c96d3810f..eef465318a3 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics-ptr.stderr @@ -4,8 +4,8 @@ error[E0658]: const generics are unstable LL | struct ConstFn; | ^ | - = note: see issue #44580 for more information - = help: add `#![feature(const_generics)]` to the crate attributes to enable + = note: see issue #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 @@ -13,8 +13,8 @@ error[E0658]: const generics are unstable LL | struct ConstPtr; | ^ | - = note: see issue #44580 for more information - = help: add `#![feature(const_generics)]` to the crate attributes to enable + = note: see issue #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 diff --git a/src/test/ui/feature-gates/feature-gate-const_generics.stderr b/src/test/ui/feature-gates/feature-gate-const_generics.stderr index 02aa1f5a4d8..f80362252f9 100644 --- a/src/test/ui/feature-gates/feature-gate-const_generics.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_generics.stderr @@ -4,8 +4,8 @@ error[E0658]: const generics are unstable LL | fn foo() {} | ^ | - = note: see issue #44580 for more information - = help: add `#![feature(const_generics)]` to the crate attributes to enable + = note: see issue #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 @@ -13,8 +13,8 @@ error[E0658]: const generics are unstable LL | struct Foo([(); X]); | ^ | - = note: see issue #44580 for more information - = help: add `#![feature(const_generics)]` to the crate attributes to enable + = note: see issue #74878 for more information + = help: add `#![feature(min_const_generics)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs new file mode 100644 index 00000000000..1e1241c7f83 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs @@ -0,0 +1,20 @@ +// 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(&self, _: F) {} +} + +pub fn crash(v: &V) +where + for<'a> &'a V: T + 'static, +{ + v.t(|| {}); //~ ERROR: higher-ranked subtype error +} + +fn main() {} diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr new file mode 100644 index 00000000000..ca632629267 --- /dev/null +++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr @@ -0,0 +1,8 @@ +error: higher-ranked subtype error + --> $DIR/issue-59311.rs:17:9 + | +LL | v.t(|| {}); + | ^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr b/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr index 2f3d48bf039..4d8a8edf4c9 100644 --- a/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr +++ b/src/test/ui/macro_backtrace/main.-Zmacro-backtrace.stderr @@ -17,20 +17,20 @@ LL | / macro_rules! pong { LL | | () => { syntax error }; | | ^^^^^ expected one of 8 possible tokens LL | | } - | |__- in this expansion of `pong!` + | |__- in this expansion of `pong!` (#2) ... LL | ping!(); - | -------- in this macro invocation + | -------- in this macro invocation (#1) | ::: $DIR/auxiliary/ping.rs:5:1 | LL | / macro_rules! ping { LL | | () => { LL | | pong!(); - | | -------- in this macro invocation + | | -------- in this macro invocation (#2) LL | | } LL | | } - | |_- in this expansion of `ping!` + | |_- in this expansion of `ping!` (#1) error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `error` --> $DIR/main.rs:10:20 diff --git a/src/test/ui/panics/issue-47429-short-backtraces.rs b/src/test/ui/panics/issue-47429-short-backtraces.rs new file mode 100644 index 00000000000..1e8c38cc342 --- /dev/null +++ b/src/test/ui/panics/issue-47429-short-backtraces.rs @@ -0,0 +1,18 @@ +// 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!() +} diff --git a/src/test/ui/panics/issue-47429-short-backtraces.run.stderr b/src/test/ui/panics/issue-47429-short-backtraces.run.stderr new file mode 100644 index 00000000000..99ee26fe55e --- /dev/null +++ b/src/test/ui/panics/issue-47429-short-backtraces.run.stderr @@ -0,0 +1,5 @@ +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. diff --git a/src/test/ui/polymorphization/closure_in_upvar/fn.rs b/src/test/ui/polymorphization/closure_in_upvar/fn.rs new file mode 100644 index 00000000000..b0b39dbd3df --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/fn.rs @@ -0,0 +1,29 @@ +// 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(); +} diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs b/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs new file mode 100644 index 00000000000..ba75f6c5a10 --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/fnmut.rs @@ -0,0 +1,34 @@ +// 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(); +} diff --git a/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs b/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs new file mode 100644 index 00000000000..e9761ad0bcb --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/fnonce.rs @@ -0,0 +1,34 @@ +// 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::::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(); +} diff --git a/src/test/ui/polymorphization/closure_in_upvar/other.rs b/src/test/ui/polymorphization/closure_in_upvar/other.rs new file mode 100644 index 00000000000..7614aa83fcd --- /dev/null +++ b/src/test/ui/polymorphization/closure_in_upvar/other.rs @@ -0,0 +1,38 @@ +// 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(); +} diff --git a/src/test/ui/polymorphization/promoted-function-1.rs b/src/test/ui/polymorphization/promoted-function-1.rs new file mode 100644 index 00000000000..2cd02673442 --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function-1.rs @@ -0,0 +1,12 @@ +// build-fail +// compile-flags: -Zpolymorphize=on +#![crate_type = "lib"] +#![feature(rustc_attrs)] + +fn foo<'a>(_: &'a ()) {} + +#[rustc_polymorphize_error] +pub fn test() { + //~^ ERROR item has unused generic parameters + foo(&()); +} diff --git a/src/test/ui/polymorphization/promoted-function-1.stderr b/src/test/ui/polymorphization/promoted-function-1.stderr new file mode 100644 index 00000000000..fcbb8694923 --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function-1.stderr @@ -0,0 +1,8 @@ +error: item has unused generic parameters + --> $DIR/promoted-function-1.rs:9:8 + | +LL | pub fn test() { + | ^^^^ - generic parameter `T` is unused + +error: aborting due to previous error + diff --git a/src/test/ui/polymorphization/promoted-function-2.rs b/src/test/ui/polymorphization/promoted-function-2.rs new file mode 100644 index 00000000000..2831f861f55 --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function-2.rs @@ -0,0 +1,16 @@ +// 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() { + //~^ ERROR item has unused generic parameters + let x = [0; 3 + 4]; +} + +pub fn caller() { + test::(); + test::>(); +} diff --git a/src/test/ui/polymorphization/promoted-function-2.stderr b/src/test/ui/polymorphization/promoted-function-2.stderr new file mode 100644 index 00000000000..38d4808c48c --- /dev/null +++ b/src/test/ui/polymorphization/promoted-function-2.stderr @@ -0,0 +1,17 @@ +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 for more information + +error: item has unused generic parameters + --> $DIR/promoted-function-2.rs:8:4 + | +LL | fn test() { + | ^^^^ - generic parameter `T` is unused + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/polymorphization/promoted-function.rs b/src/test/ui/polymorphization/promoted-function.rs index 0d3af7a89c2..a56a8e70e4c 100644 --- a/src/test/ui/polymorphization/promoted-function.rs +++ b/src/test/ui/polymorphization/promoted-function.rs @@ -1,4 +1,6 @@ // run-pass +// compile-flags:-Zpolymorphize=on + fn fop() {} fn bar() -> &'static fn() { diff --git a/src/test/ui/polymorphization/unsized_cast.rs b/src/test/ui/polymorphization/unsized_cast.rs index b8facc16070..b803fec2ccf 100644 --- a/src/test/ui/polymorphization/unsized_cast.rs +++ b/src/test/ui/polymorphization/unsized_cast.rs @@ -17,6 +17,7 @@ fn foo() { fn foo2() { 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 diff --git a/src/test/ui/polymorphization/unsized_cast.stderr b/src/test/ui/polymorphization/unsized_cast.stderr index d4727acca9a..b51cc5c719f 100644 --- a/src/test/ui/polymorphization/unsized_cast.stderr +++ b/src/test/ui/polymorphization/unsized_cast.stderr @@ -17,7 +17,7 @@ LL | (|| Box::new(|| {}) as Box)(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: item has unused generic parameters - --> $DIR/unsized_cast.rs:21:15 + --> $DIR/unsized_cast.rs:22:15 | LL | fn foo2() { | - generic parameter `T` is unused @@ -25,5 +25,19 @@ LL | fn foo2() { LL | call(&|| {}, ()); | ^^^^^ -error: aborting due to 3 previous errors +error: item has unused generic parameters + --> $DIR/unsized_cast.rs:19:5 + | +LL | fn foo2() { + | - 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 diff --git a/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.rs b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.rs new file mode 100644 index 00000000000..4601a3d4741 --- /dev/null +++ b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.rs @@ -0,0 +1,10 @@ +// 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 +} diff --git a/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.stderr b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.stderr new file mode 100644 index 00000000000..14a12003e2d --- /dev/null +++ b/src/test/ui/privacy/issue-75062-fieldless-tuple-struct.stderr @@ -0,0 +1,15 @@ +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`. diff --git a/src/test/ui/proc-macro/doc-comment-preserved.rs b/src/test/ui/proc-macro/doc-comment-preserved.rs new file mode 100644 index 00000000000..c2724ae1806 --- /dev/null +++ b/src/test/ui/proc-macro/doc-comment-preserved.rs @@ -0,0 +1,24 @@ +// check-pass +// 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)" + +#[macro_use] +extern crate test_macros; + +print_bang! { + +/** +******* +* DOC * +* DOC * +* DOC * +******* +*/ +pub struct S; + +} + +fn main() {} diff --git a/src/test/ui/proc-macro/doc-comment-preserved.stdout b/src/test/ui/proc-macro/doc-comment-preserved.stdout new file mode 100644 index 00000000000..f7904536a76 --- /dev/null +++ b/src/test/ui/proc-macro/doc-comment-preserved.stdout @@ -0,0 +1,54 @@ +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: #0 bytes(LO..HI), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "doc", + span: #0 bytes(LO..HI), + }, + Punct { + ch: '=', + spacing: Alone, + span: #0 bytes(LO..HI), + }, + Literal { + kind: Str, + symbol: "\n*******\n* DOC *\n* DOC *\n* DOC *\n*******\n", + suffix: None, + span: #0 bytes(LO..HI), + }, + ], + span: #0 bytes(LO..HI), + }, + Ident { + ident: "pub", + span: #0 bytes(LO..HI), + }, + Ident { + ident: "struct", + span: #0 bytes(LO..HI), + }, + Ident { + ident: "S", + span: #0 bytes(LO..HI), + }, + Punct { + ch: ';', + spacing: Alone, + span: #0 bytes(LO..HI), + }, +] diff --git a/src/test/ui/realloc-16687.rs b/src/test/ui/realloc-16687.rs index 0687a9ce454..bdcd47a7260 100644 --- a/src/test/ui/realloc-16687.rs +++ b/src/test/ui/realloc-16687.rs @@ -5,8 +5,9 @@ // well enough to reproduce (and illustrate) the bug from #16687. #![feature(allocator_api)] +#![feature(slice_ptr_get)] -use std::alloc::{handle_alloc_error, AllocInit, AllocRef, Global, Layout, ReallocPlacement}; +use std::alloc::{handle_alloc_error, AllocRef, Global, Layout}; use std::ptr::{self, NonNull}; fn main() { @@ -41,15 +42,13 @@ unsafe fn allocate(layout: Layout) -> *mut u8 { println!("allocate({:?})", layout); } - let memory = Global - .alloc(layout, AllocInit::Uninitialized) - .unwrap_or_else(|_| handle_alloc_error(layout)); + let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); if PRINT { - println!("allocate({:?}) = {:?}", layout, memory.ptr); + println!("allocate({:?}) = {:?}", layout, ptr); } - memory.ptr.cast().as_ptr() + ptr.as_non_null_ptr().as_ptr() } unsafe fn deallocate(ptr: *mut u8, layout: Layout) { @@ -70,21 +69,19 @@ unsafe fn reallocate(ptr: *mut u8, old: Layout, new: Layout) -> *mut u8 { NonNull::new_unchecked(ptr), old, new.size(), - ReallocPlacement::MayMove, - AllocInit::Uninitialized, ) } else { - Global.shrink(NonNull::new_unchecked(ptr), old, new.size(), ReallocPlacement::MayMove) + Global.shrink(NonNull::new_unchecked(ptr), old, new.size()) }; - let memory = memory.unwrap_or_else(|_| { + let ptr = memory.unwrap_or_else(|_| { handle_alloc_error(Layout::from_size_align_unchecked(new.size(), old.align())) }); if PRINT { - println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, memory.ptr); + println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, ptr); } - memory.ptr.cast().as_ptr() + ptr.as_non_null_ptr().as_ptr() } fn idx_to_size(i: usize) -> usize { diff --git a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr index be55890c08c..7f197a238e5 100644 --- a/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr +++ b/src/test/ui/recursion/issue-26548-recursion-via-normalize.stderr @@ -1,7 +1,7 @@ -error[E0391]: cycle detected when computing layout of `std::option::Option` +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`, completing the cycle + = note: ...which requires computing layout of `std::option::Option`... + = 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 | diff --git a/src/test/ui/regions/regions-mock-codegen.rs b/src/test/ui/regions/regions-mock-codegen.rs index 380310190be..ad4b9c352ae 100644 --- a/src/test/ui/regions/regions-mock-codegen.rs +++ b/src/test/ui/regions/regions-mock-codegen.rs @@ -4,7 +4,7 @@ // pretty-expanded FIXME #23616 #![feature(allocator_api)] -use std::alloc::{handle_alloc_error, AllocInit, AllocRef, Global, Layout}; +use std::alloc::{handle_alloc_error, AllocRef, Global, Layout}; use std::ptr::NonNull; struct arena(()); @@ -25,10 +25,8 @@ struct Ccx { fn alloc(_bcx: &arena) -> &Bcx<'_> { unsafe { let layout = Layout::new::(); - let memory = Global - .alloc(layout, AllocInit::Uninitialized) - .unwrap_or_else(|_| handle_alloc_error(layout)); - &*(memory.ptr.as_ptr() as *const _) + let ptr = Global.alloc(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + &*(ptr.as_ptr() as *const _) } } diff --git a/src/test/ui/rfc-2091-track-caller/error-with-main.rs b/src/test/ui/rfc-2091-track-caller/error-with-main.rs new file mode 100644 index 00000000000..b2ea31bb517 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-main.rs @@ -0,0 +1,4 @@ +#[track_caller] //~ ERROR `main` function is not allowed to be +fn main() { + panic!("{}: oh no", std::panic::Location::caller()); +} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-main.stderr b/src/test/ui/rfc-2091-track-caller/error-with-main.stderr new file mode 100644 index 00000000000..f05f88e7d71 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-main.stderr @@ -0,0 +1,12 @@ +error: `main` function is not allowed to be `#[track_caller]` + --> $DIR/error-with-main.rs:1:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | / fn main() { +LL | | panic!("{}: oh no", std::panic::Location::caller()); +LL | | } + | |_- `main` function is not allowed to be `#[track_caller]` + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2091-track-caller/error-with-start.rs b/src/test/ui/rfc-2091-track-caller/error-with-start.rs new file mode 100644 index 00000000000..0cab4717063 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-start.rs @@ -0,0 +1,7 @@ +#![feature(start)] + +#[start] +#[track_caller] //~ ERROR `start` is not allowed to be `#[track_caller]` +fn start(_argc: isize, _argv: *const *const u8) -> isize { + panic!("{}: oh no", std::panic::Location::caller()); +} diff --git a/src/test/ui/rfc-2091-track-caller/error-with-start.stderr b/src/test/ui/rfc-2091-track-caller/error-with-start.stderr new file mode 100644 index 00000000000..1a1f3e04491 --- /dev/null +++ b/src/test/ui/rfc-2091-track-caller/error-with-start.stderr @@ -0,0 +1,12 @@ +error: `start` is not allowed to be `#[track_caller]` + --> $DIR/error-with-start.rs:4:1 + | +LL | #[track_caller] + | ^^^^^^^^^^^^^^^ +LL | / fn start(_argc: isize, _argv: *const *const u8) -> isize { +LL | | panic!("{}: oh no", std::panic::Location::caller()); +LL | | } + | |_- `start` is not allowed to be `#[track_caller]` + +error: aborting due to previous error + diff --git a/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs b/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs index a323bd9e82b..8c436841b44 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs @@ -2,6 +2,7 @@ #![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. diff --git a/src/test/ui/simd/simd-intrinsic-generic-select.rs b/src/test/ui/simd/simd-intrinsic-generic-select.rs index 22bda4fc9d9..dc9ec5d2760 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-select.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-select.rs @@ -2,10 +2,7 @@ #![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. diff --git a/src/tools/cargo b/src/tools/cargo index 2d5c2381e4e..1653f354644 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 2d5c2381e4e50484bf281fc1bfe19743aa9eb37a +Subproject commit 1653f354644834073d6d2541e27fae94588e685e diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index e87c33d1b09..6ce36fd2360 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -2,6 +2,7 @@ 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}; @@ -249,7 +250,7 @@ fn lint_for_missing_headers<'tcx>( } } -/// 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 @@ -257,54 +258,45 @@ fn lint_for_missing_headers<'tcx>( /// 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)] @@ -318,9 +310,8 @@ fn check_attrs<'a>(cx: &LateContext<'_>, valid_idents: &FxHashSet, attrs 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)) { diff --git a/src/tools/clippy/clippy_lints/src/functions.rs b/src/tools/clippy/clippy_lints/src/functions.rs index 3ee0b3f74b8..6a141f1fc78 100644 --- a/src/tools/clippy/clippy_lints/src/functions.rs +++ b/src/tools/clippy/clippy_lints/src/functions.rs @@ -239,7 +239,7 @@ fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) { 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( @@ -262,7 +262,7 @@ fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem< 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( @@ -294,7 +294,7 @@ fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitIte 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, diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index ca1381852da..4e49bdbdd21 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -102,7 +102,7 @@ fn is_doc_hidden(attr: &Attribute) -> bool { "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 { @@ -154,7 +154,7 @@ fn find_header_span(cx: &EarlyContext<'_>, item: &Item, data: &VariantData) -> S "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 { diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index 48ab98418e4..603440c0f83 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -2,7 +2,6 @@ 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; @@ -385,7 +384,7 @@ fn check_impl_item(&mut self, cx: &EarlyContext<'_>, item: &AssocItem) { } 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, diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs index 7b673e15b76..74ccd9235de 100644 --- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs +++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs @@ -60,13 +60,14 @@ 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( diff --git a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs index 58c1103da9f..ad02bc5fd8e 100755 --- a/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs +++ b/src/tools/clippy/clippy_lints/src/utils/ast_utils.rs @@ -506,7 +506,7 @@ pub fn eq_attr(l: &Attribute, r: &Attribute) -> bool { 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, } diff --git a/src/tools/clippy/clippy_lints/src/utils/attrs.rs b/src/tools/clippy/clippy_lints/src/utils/attrs.rs index 4bb4b087c55..407527251da 100644 --- a/src/tools/clippy/clippy_lints/src/utils/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/utils/attrs.rs @@ -1,5 +1,4 @@ use rustc_ast::ast; -use rustc_ast::expand::is_proc_macro_attr; use rustc_errors::Applicability; use rustc_session::Session; use std::str::FromStr; @@ -126,6 +125,6 @@ fn parse_attrs(sess: &Session, attrs: &[ast::Attribute], name: &' /// 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)) } diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index 3f8e15d9029..95a12fe1935 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -932,7 +932,7 @@ fn are_refutable<'a, I: Iterator>>(cx: &LateContext<'_>, mut /// 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. diff --git a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr index ac5f0d0a39e..2b3f9be2dfb 100644 --- a/src/tools/clippy/tests/ui/indexing_slicing_index.stderr +++ b/src/tools/clippy/tests/ui/indexing_slicing_index.stderr @@ -1,23 +1,3 @@ -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 | @@ -75,5 +55,5 @@ LL | v[M]; | = help: Consider using `.get(n)` or `.get_mut(n)` instead -error: aborting due to 10 previous errors +error: aborting due to 7 previous errors diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 9269a63b41a..848bd3a43e8 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -169,7 +169,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } /// 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, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 047fbe9da14..edbb8372633 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -827,6 +827,7 @@ fn parse_cfg_name_directive(&self, line: &str, prefix: &str) -> ParsedNameDirect 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", diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 940e16720f6..7f49cb913b1 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1885,7 +1885,8 @@ fn make_compile_args( 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 { @@ -3246,8 +3247,19 @@ fn check_mir_dump(&self) { } 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(); @@ -3573,6 +3585,7 @@ pub fn fatal(&self, err: Option<&str>) -> ! { } } +#[derive(Debug)] enum TargetLocation { ThisFile(PathBuf), ThisDirectory(PathBuf), diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 0437ff8c944..ddd7941b114 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -99,6 +99,20 @@ 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 @@ -125,6 +139,12 @@ pub fn get_arch(triple: &str) -> &'static str { 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 } } diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index bd9f8fb0450..ff6923b3797 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -1,6 +1,5 @@ #![feature(rustc_private)] -extern crate rustc_ast; extern crate rustc_driver; extern crate rustc_span; @@ -284,7 +283,7 @@ fn parse_args() -> (OutputFormat, PathBuf) { 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()); } diff --git a/src/tools/miri b/src/tools/miri index 55bdb317465..cf633d0e897 160000 --- a/src/tools/miri +++ b/src/tools/miri @@ -1 +1 @@ -Subproject commit 55bdb3174653039f47362742f8dc941bfc086e8f +Subproject commit cf633d0e897c065381b7b7d14984830176caf8b2 diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index c0631fcedd3..55e2d7cf827 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -42,7 +42,7 @@ MAINTAINERS = { 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'], diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 51f135d3761..9c36d853ef7 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -16,8 +16,7 @@ ]; // 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", "E0749"]; fn check_error_code_explanation( f: &str, diff --git a/src/tools/unicode-table-generator/src/main.rs b/src/tools/unicode-table-generator/src/main.rs index eabbcee9d73..d2d1807b3bb 100644 --- a/src/tools/unicode-table-generator/src/main.rs +++ b/src/tools/unicode-table-generator/src/main.rs @@ -15,7 +15,7 @@ //! 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).