Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions compiler/rustc_resolve/src/check_unused.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,13 @@ impl<'a, 'ra, 'tcx> AsMut<Resolver<'ra, 'tcx>> for UnusedImportCheckVisitor<'a,
}

impl<'a, 'ra, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'ra, 'tcx> {
// Don't walk into attributes because imports can appear
// inside (e.g #[doc = {use std::{io,fmt};}]). They have
// a different owner, so they will cause an ICE if we visit
// them. Note that this doc attribute is not valid and will
// be rejected during AST lowering.
fn visit_attribute(&mut self, _: &'a rustc_ast::Attribute) {}

fn visit_item(&mut self, item: &'a ast::Item) {
self.item_span = item.span_with_attributes();
match &item.kind {
Expand Down
28 changes: 18 additions & 10 deletions library/alloc/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,30 +43,38 @@ unsafe extern "Rust" {
fn __rust_no_alloc_shim_is_unstable_v2();
}

/// The global memory allocator.
/// A wrapper for the global allocator.
///
/// This type implements the [`Allocator`] trait by forwarding calls
/// to the allocator registered with the `#[global_allocator]` attribute
/// if there is one, or the `std` crate’s default.
///
/// `Global` is not "the global allocator", but a wrapper for it.
/// If the global allocator used `Global`, it would call itself recursively.
/// To avoid this, `Global` does not implement [`GlobalAlloc`].
///
/// Similar to [`alloc`], [`dealloc`], and the other global allocation functions,
/// the way in which calls are forwarded to the allocator registered with
/// when and how calls are forwarded to the allocator registered with
/// `#[global_allocator]` is unspecified. See their safety docs for more information.
///
/// This allocator must be treated like an opaque allocator that only guarantees
/// the contract described in the docs of [`Allocator`], as well as the following
/// things:
/// In particular, even if you know which allocator was registered
/// as the global allocator, calling it directly is not the same as calling
/// `Global`. You cannot deallocate memory from one using the other.
///
/// `Global` must be treated like an opaque allocator that only guarantees the contract
/// described in the docs of [`Allocator`], as well as the following:
/// * All instances of `Global` are [*equivalent*].
/// * Allocations from `Global` are only invalidated by calls to de-/reallocating functions.
/// If no such call is made, then the allocation will live for the rest of the program.
/// * The global allocation functions are equivalent to the methods on `Global`, except
/// that they disallow zero-sized allocations, and implicitly ignore any returned
/// excess size.
/// * The global allocation functions in the [`alloc`](self) module are equivalent to the
/// methods on `Global`, except that they disallow zero-sized allocations, and implicitly
/// ignore any returned excess size.
/// In particular, you may deallocate memory from [`alloc::alloc`](self::alloc) using
/// [`Global.deallocate`](Global::deallocate) and vice-versa.
///
/// Note that the current implementation of `Global` does not take advantage of
/// some features of [`Allocator`], such as zero-sized allocations (which currently always
/// some features of [`Allocator`], such as zero-sized allocations (which currently
/// return a dangling pointer) and overallocating.
///
/// This may change in the future. You must not rely on it for correctness!
///
/// [*equivalent*]: Allocator#equivalent-allocators
Expand Down
41 changes: 22 additions & 19 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -802,7 +802,7 @@ impl String {
let (chunks, []) = v.as_chunks::<2>() else {
return Err(FromUtf16Error { kind: FromUtf16ErrorKind::OddBytes });
};
// ignore-tidy-undocumented-unsafe
// SAFETY: The aligned part of `v` can be transmuted into a valid u16 slice.
match (cfg!(target_endian = "little"), unsafe { v.align_to::<u16>() }) {
(true, ([], v, [])) => Self::from_utf16(v),
_ => {
Expand Down Expand Up @@ -838,7 +838,7 @@ impl String {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "str_from_utf16_endian", since = "1.98.0")]
pub fn from_utf16le_lossy(v: &[u8]) -> String {
// ignore-tidy-undocumented-unsafe
// SAFETY: The aligned part of `v` can be transmuted into a valid u16 slice.
match (cfg!(target_endian = "little"), unsafe { v.align_to::<u16>() }) {
(true, ([], v, [])) => Self::from_utf16_lossy(v),
(true, ([], v, [_remainder])) => Self::from_utf16_lossy(v) + "\u{FFFD}",
Expand Down Expand Up @@ -877,7 +877,7 @@ impl String {
let (chunks, []) = v.as_chunks::<2>() else {
return Err(FromUtf16Error { kind: FromUtf16ErrorKind::OddBytes });
};
// ignore-tidy-undocumented-unsafe
// SAFETY: The aligned part of `v` can be transmuted into a valid u16 slice.
match (cfg!(target_endian = "big"), unsafe { v.align_to::<u16>() }) {
(true, ([], v, [])) => Self::from_utf16(v),
_ => {
Expand Down Expand Up @@ -913,7 +913,7 @@ impl String {
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "str_from_utf16_endian", since = "1.98.0")]
pub fn from_utf16be_lossy(v: &[u8]) -> String {
// ignore-tidy-undocumented-unsafe
// SAFETY: The aligned part of `v` can be transmuted into a valid u16 slice.
match (cfg!(target_endian = "big"), unsafe { v.align_to::<u16>() }) {
(true, ([], v, [])) => Self::from_utf16_lossy(v),
(true, ([], v, [_remainder])) => Self::from_utf16_lossy(v) + "\u{FFFD}",
Expand Down Expand Up @@ -1143,7 +1143,8 @@ impl String {
let additional: Saturating<usize> = slice.iter().map(|x| Saturating(x.len())).sum();
self.reserve(additional.0);
let (ptr, len, cap) = core::mem::take(self).into_raw_parts();
// ignore-tidy-undocumented-unsafe
// SAFETY: `self` have reserved enough space for strs in `slice`, and we are copying from valid UTF-8 slices.
// Therefore all unsafe operations are safe.
unsafe {
let mut dst = ptr.add(len);
for new in slice {
Expand Down Expand Up @@ -1532,7 +1533,7 @@ impl String {
pub fn pop(&mut self) -> Option<char> {
let ch = self.chars().rev().next()?;
let newlen = self.len() - ch.len_utf8();
// ignore-tidy-undocumented-unsafe
// SAFETY: `newlen` is less than old length.
unsafe {
self.vec.set_len(newlen);
}
Expand Down Expand Up @@ -1571,7 +1572,11 @@ impl String {

let next = idx + ch.len_utf8();
let len = self.len();
// ignore-tidy-undocumented-unsafe
// SAFETY:
// * Since `next` is not bigger than `len`, `self.vec.as_ptr().add(next)`
// is valid for reads and `self.vec.as_mut_ptr().add(idx)` is valid for writes.
// Both pointers are valid for `len - next` bytes.
// * new length is less than old length.
unsafe {
ptr::copy(self.vec.as_ptr().add(next), self.vec.as_mut_ptr().add(idx), len - next);
self.vec.set_len(len - (next - idx));
Expand Down Expand Up @@ -1645,7 +1650,7 @@ impl String {
len += count;
}

// ignore-tidy-undocumented-unsafe
// SAFETY: `len` is less than or equal to the original length of the string.
unsafe {
self.vec.set_len(len);
}
Expand Down Expand Up @@ -1954,7 +1959,7 @@ impl String {
pub fn split_off(&mut self, at: usize) -> String {
assert!(self.is_char_boundary(at));
let other = self.vec.split_off(at);
// ignore-tidy-undocumented-unsafe
// SAFETY: `other` contains only valid UTF-8 because `at` is on a `UTF-8` code point boundary.
unsafe { String::from_utf8_unchecked(other) }
}

Expand Down Expand Up @@ -2224,7 +2229,7 @@ impl String {
#[inline]
pub fn into_boxed_str(self) -> Box<str> {
let slice = self.vec.into_boxed_slice();
// ignore-tidy-undocumented-unsafe
// SAFETY: `slice` contains only valid UTF-8 because `String` is guaranteed to be valid UTF-8.
unsafe { from_boxed_utf8_unchecked(slice) }
}

Expand Down Expand Up @@ -2256,7 +2261,7 @@ impl String {
#[inline]
pub fn leak<'a>(self) -> &'a mut str {
let slice = self.vec.leak();
// ignore-tidy-undocumented-unsafe
// SAFETY: `slice` contains only valid UTF-8 because `String` is guaranteed to be valid UTF-8.
unsafe { from_utf8_unchecked_mut(slice) }
}
}
Expand Down Expand Up @@ -3586,14 +3591,12 @@ unsafe impl Send for Drain<'_> {}
#[stable(feature = "drain", since = "1.6.0")]
impl Drop for Drain<'_> {
fn drop(&mut self) {
// ignore-tidy-undocumented-unsafe
unsafe {
// Use Vec::drain. "Reaffirm" the bounds checks to avoid
// panic code being inserted again.
let self_vec = (*self.string).as_mut_vec();
if self.start <= self.end && self.end <= self_vec.len() {
self_vec.drain(self.start..self.end);
}
// Use Vec::drain. "Reaffirm" the bounds checks to avoid
// panic code being inserted again.
// SAFETY: We only use the returned Vec to call drain.
let self_vec = unsafe { &mut *(*self.string).as_mut_vec() };
if self.start <= self.end && self.end <= self_vec.len() {
self_vec.drain(self.start..self.end);
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions tests/ui/attributes/use-tree-in-docs.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Don't ICE when use tree appears in docs. (#163355)
#![feature(generic_assert)]
#[doc = assert !(b)]
//~^ ERROR attribute value must be a literal
use std as x;

fn main(){}
8 changes: 8 additions & 0 deletions tests/ui/attributes/use-tree-in-docs.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
error: attribute value must be a literal
--> $DIR/use-tree-in-docs.rs:3:9
|
LL | #[doc = assert !(b)]
| ^^^^^^^^^^^

error: aborting due to 1 previous error

Loading