diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index ca78640f135f4..97cc76d833e9e 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -501,14 +501,14 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { } if let Some(def_id) = child.res.opt_def_id() { + let mut fallback = false; + if child.ident.name == kw::Underscore { - fallback_map.push((def_id, parent)); - return; + fallback = true; } if tcx.is_doc_hidden(parent) { - fallback_map.push((def_id, parent)); - return; + fallback = true; } // If the re-export itself is `#[doc(hidden)]`, deprioritize it. @@ -519,20 +519,30 @@ pub(in crate::rmeta) fn provide(providers: &mut Providers) { .and_then(|r| r.id()) .is_some_and(|id| tcx.is_doc_hidden(id)) { - fallback_map.push((def_id, parent)); - return; + fallback = true; } match visible_parent_map.entry(def_id) { Entry::Occupied(mut entry) => { - // If `child` is defined in crate `cnum`, ensure - // that it is mapped to a parent in `cnum`. - if def_id.is_local() && entry.get().is_local() { - entry.insert(parent); + if !fallback { + // If `child` is defined in crate `cnum`, ensure + // that it is mapped to a parent in `cnum`. + if def_id.is_local() && entry.get().is_local() { + entry.insert(parent); + } } } Entry::Vacant(entry) => { - entry.insert(parent); + if fallback { + // We do all of the same steps to fallback entries as to + // preferred entries, except for recording them in a separate map. + // It is important to not return early in the fallback cases to + // ensure that we extend the BFS to the children of fallback items. + fallback_map.push((def_id, parent)); + } else { + entry.insert(parent); + } + if child.res.module_like_def_id().is_some() { bfs_queue.push_back(def_id); } diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 6f0faffa32984..c582c06d8f4bb 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -105,7 +105,7 @@ impl X86InlineAsmRegClass { pub fn supported_types( self, arch: InlineAsmArch, - allow_experimental_reg: bool, + _allow_experimental_reg: bool, ) -> &'static [(InlineAsmType, Option)] { match self { Self::reg | Self::reg_abcd => { @@ -117,48 +117,24 @@ impl X86InlineAsmRegClass { } Self::reg_byte => types! { _: I8; }, Self::xmm_reg => { - if allow_experimental_reg { - types! { - sse: I32, I64, I128, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); - } - } else { - types! { - sse: I32, I64, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); - } + types! { + sse: I32, I64, I128, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); } } Self::ymm_reg => { - if allow_experimental_reg { - types! { - avx: I32, I64, I128, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4); - } - } else { - types! { - avx: I32, I64, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4); - } + types! { + avx: I32, I64, I128, F16, F32, F64, F128, + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4); } } Self::zmm_reg => { - if allow_experimental_reg { - types! { - avx512f: I32, I64, I128, F16, F32, F64, F128, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4), - VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF16(32), VecF32(16), VecF64(8); - } - } else { - types! { - avx512f: I32, I64, F16, F32, F64, F128, + types! { + avx512f: I32, I64, I128, F16, F32, F64, F128, VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2), VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF16(16), VecF32(8), VecF64(4), VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF16(32), VecF32(16), VecF64(8); - } } } diff --git a/library/alloc/src/io/mod.rs b/library/alloc/src/io/mod.rs index 5c043240daba8..44d780292317f 100644 --- a/library/alloc/src/io/mod.rs +++ b/library/alloc/src/io/mod.rs @@ -1,4 +1,179 @@ //! Traits, helpers, and type definitions for core I/O functionality. +//! +//! The `io` module contains a number of common things you'll need +//! when doing input and output. The most core part of this module is +//! the [`Read`] and [`Write`] traits, which provide the +//! most general interface for reading and writing input and output. +//! +//! ## Read and Write +//! +//! Because they are traits, [`Read`] and [`Write`] are implemented by a number +//! of other types, and you can implement them for your types too. As such, +//! you'll see a few different types of I/O throughout the documentation in +//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For +//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on +//! [`File`]s: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let mut f = File::open("foo.txt")?; +//! let mut buffer = [0; 10]; +//! +//! // read up to 10 bytes +//! let n = f.read(&mut buffer)?; +//! +//! println!("The bytes: {:?}", &buffer[..n]); +//! Ok(()) +//! } +//! ``` +//! +//! [`Read`] and [`Write`] are so important, implementors of the two traits have a +//! nickname: readers and writers. So you'll sometimes see 'a reader' instead +//! of 'a type that implements the [`Read`] trait'. Much easier! +//! +//! ## Seek and BufRead +//! +//! Beyond that, there are two important traits that are provided: [`Seek`] +//! and [`BufRead`]. Both of these build on top of a reader to control +//! how the reading happens. [`Seek`] lets you control where the next byte is +//! coming from: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::SeekFrom; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let mut f = File::open("foo.txt")?; +//! let mut buffer = [0; 10]; +//! +//! // skip to the last 10 bytes of the file +//! f.seek(SeekFrom::End(-10))?; +//! +//! // read up to 10 bytes +//! let n = f.read(&mut buffer)?; +//! +//! println!("The bytes: {:?}", &buffer[..n]); +//! Ok(()) +//! } +//! ``` +//! +//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but +//! to show it off, we'll need to talk about buffers in general. Keep reading! +//! +//! ## BufReader and BufWriter +//! +//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be +//! making near-constant calls to the operating system. To help with this, +//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap +//! readers and writers. The wrapper uses a buffer, reducing the number of +//! calls and providing nicer methods for accessing exactly what you want. +//! +//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra +//! methods to any reader: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let mut reader = BufReader::new(f); +//! let mut buffer = String::new(); +//! +//! // read a line into buffer +//! reader.read_line(&mut buffer)?; +//! +//! println!("{buffer}"); +//! Ok(()) +//! } +//! ``` +//! +//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call +//! to [`write`][`Write::write`]: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufWriter; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let f = File::create("foo.txt")?; +//! { +//! let mut writer = BufWriter::new(f); +//! +//! // write a byte to the buffer +//! writer.write(&[42])?; +//! +//! } // the buffer is flushed once writer goes out of scope +//! +//! Ok(()) +//! } +//! ``` +//! +//! ## Iterator types +//! +//! A large number of the structures provided by `std::io` are for various +//! ways of iterating over I/O. For example, [`Lines`] is used to split over +//! lines: +//! +//! ```no_run +//! use std::io; +//! use std::io::prelude::*; +//! use std::io::BufReader; +//! use std::fs::File; +//! +//! fn main() -> io::Result<()> { +//! let f = File::open("foo.txt")?; +//! let reader = BufReader::new(f); +//! +//! for line in reader.lines() { +//! println!("{}", line?); +//! } +//! Ok(()) +//! } +//! ``` +//! +//! ## io::Result +//! +//! Last, but certainly not least, is [`io::Result`]. This type is used +//! as the return type of many `std::io` functions that can cause an error, and +//! can be returned from your own functions as well. Many of the examples in this +//! module use the [`?` operator]: +//! +//! ```no_run +//! use std::io; +//! +//! # #[allow(dead_code)] +//! fn read_input() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! io::stdin().read_line(&mut input)?; +//! +//! println!("You typed: {}", input.trim()); +//! +//! Ok(()) +//! } +//! ``` +//! +//! The return type of `read_input()`, [`io::Result<()>`][`io::Result`], is a very +//! common type for functions which don't have a 'real' return value, but do want to +//! return errors if they happen. In this case, the only purpose of this function is +//! to read the line and print it, so we use `()`. +//! +//! [`File`]: ../../std/fs/struct.File.html +//! [`TcpStream`]: ../../std/net/struct.TcpStream.html +//! [`Vec`]: crate::vec::Vec +//! [`io::Result`]: self::Result +//! [`?` operator]: ../../book/appendix-02-operators.html mod buf_read; mod buffered; @@ -6,6 +181,8 @@ mod copy; mod cursor; mod error; mod impls; +#[unstable(feature = "alloc_io", issue = "154046")] +pub mod prelude; mod read; mod util; diff --git a/library/alloc/src/io/prelude.rs b/library/alloc/src/io/prelude.rs new file mode 100644 index 0000000000000..86ae040d1d6f6 --- /dev/null +++ b/library/alloc/src/io/prelude.rs @@ -0,0 +1,12 @@ +//! The I/O Prelude. +//! +//! The purpose of this module is to alleviate imports of many common I/O traits +//! by adding a glob import to the top of I/O heavy modules: +//! +//! ``` +//! # #![allow(unused_imports)] +//! use std::io::prelude::*; +//! ``` + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::io::{BufRead, Read, Seek, Write}; diff --git a/library/alloc/src/io/read.rs b/library/alloc/src/io/read.rs index 490a55f9d10dc..fe1a8d11ccefe 100644 --- a/library/alloc/src/io/read.rs +++ b/library/alloc/src/io/read.rs @@ -84,6 +84,7 @@ use crate::vec::Vec; #[stable(feature = "rust1", since = "1.0.0")] #[doc(notable_trait)] #[cfg_attr(not(test), rustc_diagnostic_item = "IoRead")] +#[rustc_must_implement_one_of(read, read_buf)] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -164,7 +165,10 @@ pub trait Read { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - fn read(&mut self, buf: &mut [u8]) -> Result; + fn read(&mut self, buf: &mut [u8]) -> Result { + let mut buf = BorrowedBuf::from(buf); + self.read_buf(buf.unfilled()).map(|()| buf.len()) + } /// Like `read`, except that it reads into a slice of buffers. /// diff --git a/library/std/src/io/impls/tests.rs b/library/alloctests/benches/io.rs similarity index 59% rename from library/std/src/io/impls/tests.rs rename to library/alloctests/benches/io.rs index d1cd84a67ada5..f2e3f2cd3c998 100644 --- a/library/std/src/io/impls/tests.rs +++ b/library/alloctests/benches/io.rs @@ -1,4 +1,4 @@ -use crate::io::prelude::*; +use std::io::prelude::*; #[bench] fn bench_read_slice(b: &mut test::Bencher) { @@ -55,3 +55,26 @@ fn bench_write_vec(b: &mut test::Bencher) { } }) } + +#[bench] +#[cfg(unix)] +#[cfg_attr(target_os = "emscripten", ignore)] // no /dev +fn bench_copy_buf_reader(b: &mut test::Bencher) { + use std::fs::{File, OpenOptions}; + + let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed"); + // use dyn to avoid specializations unrelated to readbuf + let dyn_in = &mut file_in as &mut dyn Read; + let mut reader = std::io::BufReader::with_capacity(256 * 1024, dyn_in.take(0)); + let mut writer = + OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed"); + + const BYTES: u64 = 1024 * 1024; + + b.bytes = BYTES; + + b.iter(|| { + reader.get_mut().set_limit(BYTES); + std::io::copy(&mut reader, &mut writer).unwrap() + }); +} diff --git a/library/alloctests/benches/lib.rs b/library/alloctests/benches/lib.rs index 4b7139d943593..974b389a765d5 100644 --- a/library/alloctests/benches/lib.rs +++ b/library/alloctests/benches/lib.rs @@ -12,6 +12,7 @@ extern crate test; mod binary_heap; mod btree; +mod io; mod linked_list; mod slice; mod str; diff --git a/library/std/src/io/buffered/tests.rs b/library/alloctests/tests/io/buffered.rs similarity index 98% rename from library/std/src/io/buffered/tests.rs rename to library/alloctests/tests/io/buffered.rs index ff4585a60cae9..0abaa63870e15 100644 --- a/library/std/src/io/buffered/tests.rs +++ b/library/alloctests/tests/io/buffered.rs @@ -1,10 +1,14 @@ -use crate::io::prelude::*; -use crate::io::{ - self, BorrowedBuf, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom, +//! Tests for buffering wrappers for I/O traits + +use alloc::io::{ + self, BorrowedBuf, BufRead, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, Read, Seek, + SeekFrom, Write, }; -use crate::mem::MaybeUninit; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::{panic, thread}; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicUsize, Ordering}; +use std::{panic, thread}; + +extern crate test; /// A dummy reader intended at testing short-reads propagation. pub struct ShortReader { @@ -488,7 +492,7 @@ fn dont_panic_in_drop_on_panicked_flush() { } #[test] -#[cfg_attr(any(target_os = "emscripten", target_os = "wasi"), ignore)] // no threads +#[cfg_attr(not(panic = "unwind"), ignore = "test requires unwinding support")] fn panic_in_write_doesnt_flush_in_drop() { static WRITES: AtomicUsize = AtomicUsize::new(0); @@ -504,12 +508,11 @@ fn panic_in_write_doesnt_flush_in_drop() { } } - thread::spawn(|| { + panic::catch_unwind(panic::AssertUnwindSafe(|| { let mut writer = BufWriter::new(PanicWriter); let _ = writer.write(b"hello world"); let _ = writer.flush(); - }) - .join() + })) .unwrap_err(); assert_eq!(WRITES.load(Ordering::SeqCst), 1); @@ -681,7 +684,7 @@ fn line_vectored() { #[test] fn line_vectored_partial_and_errors() { - use crate::collections::VecDeque; + use alloc::collections::VecDeque; enum Call { Write { inputs: Vec<&'static [u8]>, output: io::Result }, @@ -1150,7 +1153,7 @@ struct WriteRecorder { impl Write for WriteRecorder { fn write(&mut self, buf: &[u8]) -> io::Result { - use crate::str::from_utf8; + use core::str::from_utf8; self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string())); Ok(buf.len()) @@ -1183,7 +1186,7 @@ fn single_formatted_write() { fn bufreader_full_initialize() { struct OneByteReader; impl Read for OneByteReader { - fn read(&mut self, buf: &mut [u8]) -> crate::io::Result { + fn read(&mut self, buf: &mut [u8]) -> alloc::io::Result { if buf.len() > 0 { buf[0] = 0; Ok(1) @@ -1206,7 +1209,7 @@ fn bufreader_full_initialize() { /// This is a regression test for https://github.com/rust-lang/rust/issues/127584. #[test] fn bufwriter_aliasing() { - use crate::io::{BufWriter, Cursor}; + use alloc::io::{BufWriter, Cursor}; let mut v = vec![0; 1024]; let c = Cursor::new(&mut v); let w = BufWriter::new(Box::new(c)); diff --git a/library/std/src/io/copy/tests.rs b/library/alloctests/tests/io/copy.rs similarity index 74% rename from library/std/src/io/copy/tests.rs rename to library/alloctests/tests/io/copy.rs index 7bdba3a04416e..485deeaea80e7 100644 --- a/library/std/src/io/copy/tests.rs +++ b/library/alloctests/tests/io/copy.rs @@ -1,7 +1,6 @@ -use crate::cmp::{max, min}; -use crate::collections::VecDeque; -use crate::io; -use crate::io::*; +use alloc::collections::VecDeque; +use alloc::io::{self, *}; +use core::cmp::{max, min}; #[test] fn copy_copies() { @@ -65,7 +64,7 @@ fn copy_specializes_bufreader() { let mut buffered = BufReader::with_capacity(256 * 1024, Cursor::new(&mut source)); let mut sink = Vec::new(); - assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); + assert_eq!(io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); assert_eq!(source.as_slice(), sink.as_slice()); let buf_sz = 71 * 1024; @@ -73,7 +72,7 @@ fn copy_specializes_bufreader() { let mut buffered = BufReader::with_capacity(buf_sz, Cursor::new(&mut source)); let mut sink = WriteObserver { observed_buffer: 0 }; - assert_eq!(crate::io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); + assert_eq!(io::copy(&mut buffered, &mut sink).unwrap(), source.len() as u64); assert_eq!( sink.observed_buffer, buf_sz, "expected a large buffer to be provided to the writer" @@ -117,32 +116,3 @@ fn copy_specializes_from_slice() { assert_eq!(60 * 1024u64, io::copy(&mut source, &mut sink).unwrap()); assert_eq!(60 * 1024, sink.observed_buffer); } - -#[cfg(unix)] -mod io_benches { - use test::Bencher; - - use crate::fs::{File, OpenOptions}; - use crate::io::BufReader; - use crate::io::prelude::*; - - #[bench] - #[cfg_attr(target_os = "emscripten", ignore)] // no /dev - fn bench_copy_buf_reader(b: &mut Bencher) { - let mut file_in = File::open("/dev/zero").expect("opening /dev/zero failed"); - // use dyn to avoid specializations unrelated to readbuf - let dyn_in = &mut file_in as &mut dyn Read; - let mut reader = BufReader::with_capacity(256 * 1024, dyn_in.take(0)); - let mut writer = - OpenOptions::new().write(true).open("/dev/null").expect("opening /dev/null failed"); - - const BYTES: u64 = 1024 * 1024; - - b.bytes = BYTES; - - b.iter(|| { - reader.get_mut().set_limit(BYTES); - crate::io::copy(&mut reader, &mut writer).unwrap() - }); - } -} diff --git a/library/std/src/io/cursor/tests.rs b/library/alloctests/tests/io/cursor.rs similarity index 99% rename from library/std/src/io/cursor/tests.rs rename to library/alloctests/tests/io/cursor.rs index d7c203c297fe6..5e863f29af53c 100644 --- a/library/std/src/io/cursor/tests.rs +++ b/library/alloctests/tests/io/cursor.rs @@ -1,5 +1,6 @@ -use crate::io::prelude::*; -use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom}; +use alloc::io::{Cursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; + +extern crate test; #[test] fn test_vec_writer() { diff --git a/library/std/src/io/tests.rs b/library/alloctests/tests/io/mod.rs similarity index 98% rename from library/std/src/io/tests.rs rename to library/alloctests/tests/io/mod.rs index 3b4f871268cd1..712e322d79f1c 100644 --- a/library/std/src/io/tests.rs +++ b/library/alloctests/tests/io/mod.rs @@ -1,7 +1,16 @@ -use super::{BorrowedBuf, Cursor, SeekFrom, repeat}; -use crate::cmp::{self, min}; -use crate::io::{self, BufRead, BufReader, DEFAULT_BUF_SIZE, IoSlice, Read, Seek, Write}; -use crate::mem::MaybeUninit; +mod buffered; +mod copy; +mod cursor; +mod util; + +use alloc::io::{ + self, BorrowedBuf, BufRead, BufReader, Cursor, DEFAULT_BUF_SIZE, IoSlice, Read, Seek, SeekFrom, + Write, repeat, +}; +use core::cmp::{self, min}; +use core::mem::MaybeUninit; + +extern crate test; #[test] fn read_until() { @@ -270,7 +279,7 @@ fn chain_bufread() { #[test] fn chain_splitted_char() { let chain = b"\xc3".chain(b"\xa9".as_slice()); - assert_eq!(crate::io::read_to_string(chain).unwrap(), "é"); + assert_eq!(alloc::io::read_to_string(chain).unwrap(), "é"); let mut chain = b"\xc3".chain(b"\xa9\n".as_slice()); let mut buf = String::new(); @@ -360,7 +369,7 @@ fn bench_read_to_end(b: &mut test::Bencher) { b.iter(|| { let mut lr = repeat(1).take(10000000); let mut vec = Vec::with_capacity(1024); - super::default_read_to_end(&mut lr, &mut vec, None) + alloc::io::default_read_to_end(&mut lr, &mut vec, None) }); } diff --git a/library/std/src/io/util/tests.rs b/library/alloctests/tests/io/util.rs similarity index 96% rename from library/std/src/io/util/tests.rs rename to library/alloctests/tests/io/util.rs index ed1d6891577da..52e0c3013dde7 100644 --- a/library/std/src/io/util/tests.rs +++ b/library/alloctests/tests/io/util.rs @@ -1,9 +1,9 @@ -use crate::fmt; -use crate::io::prelude::*; -use crate::io::{ - BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Repeat, SeekFrom, Sink, empty, repeat, sink, +use alloc::io::{ + BorrowedBuf, Empty, ErrorKind, IoSlice, IoSliceMut, Read, Repeat, Seek, SeekFrom, Sink, Write, + empty, repeat, sink, }; -use crate::mem::MaybeUninit; +use core::fmt; +use core::mem::MaybeUninit; struct ErrorDisplay; diff --git a/library/alloctests/tests/lib.rs b/library/alloctests/tests/lib.rs index 7ccc8d9c6a115..eb9ea287d950f 100644 --- a/library/alloctests/tests/lib.rs +++ b/library/alloctests/tests/lib.rs @@ -2,23 +2,31 @@ #![allow(internal_features)] #![deny(implicit_provenance_casts)] #![deny(unsafe_op_in_unsafe_fn)] +#![feature(alloc_io)] #![feature(allocator_api)] #![feature(binary_heap_drain_sorted)] #![feature(binary_heap_into_iter_sorted)] #![feature(binary_heap_pop_if)] +#![feature(borrowed_buf_init)] +#![feature(buf_read_has_data_left)] +#![feature(can_vector)] #![feature(casefold)] #![feature(const_btree_len)] #![feature(const_cmp)] #![feature(const_heap)] #![feature(const_trait_impl)] #![feature(core_intrinsics)] +#![feature(core_io_borrowed_buf)] +#![feature(core_io_internals)] #![feature(cow_is_borrowed)] +#![feature(cursor_split)] #![feature(deque_extend_front)] #![feature(downcast_unchecked)] #![feature(drain_keep_rest)] #![feature(exact_size_is_empty)] #![feature(hashmap_internals)] #![feature(inplace_iteration)] +#![feature(io_const_error)] #![feature(iter_advance_by)] #![feature(iter_array_chunks)] #![feature(iter_next_chunk)] @@ -28,6 +36,9 @@ #![feature(map_try_insert)] #![feature(pattern)] #![feature(ptr_cast_slice)] +#![feature(read_buf)] +#![feature(seek_io_take_position)] +#![feature(seek_stream_len)] #![feature(slice_partial_sort_unstable)] #![feature(slice_partition_dedup)] #![feature(slice_ptr_get)] @@ -48,6 +59,7 @@ #![feature(vec_deque_retain_range)] #![feature(vec_peek_mut)] #![feature(vec_try_remove)] +#![feature(write_all_vectored)] // tidy-alphabetical-end extern crate alloc; @@ -67,6 +79,7 @@ mod const_fns; mod cow_str; mod fmt; mod heap; +mod io; mod linked_list; mod misc_tests; mod num; diff --git a/library/core/src/io/mod.rs b/library/core/src/io/mod.rs index 0134540ae86c8..a44d271535a9e 100644 --- a/library/core/src/io/mod.rs +++ b/library/core/src/io/mod.rs @@ -5,6 +5,8 @@ mod cursor; mod error; mod impls; mod io_slice; +#[unstable(feature = "core_io", issue = "154046")] +pub mod prelude; mod seek; mod size_hint; mod util; diff --git a/library/core/src/io/prelude.rs b/library/core/src/io/prelude.rs new file mode 100644 index 0000000000000..15dacaa3a4fa0 --- /dev/null +++ b/library/core/src/io/prelude.rs @@ -0,0 +1,12 @@ +//! The I/O Prelude. +//! +//! The purpose of this module is to alleviate imports of many common I/O traits +//! by adding a glob import to the top of I/O heavy modules: +//! +//! ``` +//! # #![allow(unused_imports)] +//! use std::io::prelude::*; +//! ``` + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::io::{Seek, Write}; diff --git a/library/core/src/io/util.rs b/library/core/src/io/util.rs index b022d876eb8f5..07173f13eb08b 100644 --- a/library/core/src/io/util.rs +++ b/library/core/src/io/util.rs @@ -130,7 +130,7 @@ impl Seek for Empty { /// [`Ok(0)`]: Ok /// /// [`write`]: crate::io::Write::write -/// [`read`]: ../../std/io/trait.Read.html#tymethod.read +/// [`read`]: ../../std/io/trait.Read.html#method.read /// /// # Examples /// diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index ef956e8bdef5d..f614c31430745 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -4,6 +4,7 @@ use crate::iter::adapters::zip::try_get_unchecked; use crate::iter::{ FusedIterator, TrustedFused, TrustedLen, TrustedRandomAccess, TrustedRandomAccessNoCoerce, }; +use crate::num::NonZero; use crate::ops::Try; /// An iterator that yields `None` forever after the underlying iterator @@ -50,6 +51,10 @@ where FuseImpl::next(self) } + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + FuseImpl::advance_by(self, n) + } + #[inline] fn nth(&mut self, n: usize) -> Option { FuseImpl::nth(self, n) @@ -259,6 +264,7 @@ trait FuseImpl { // Functions specific to any normal Iterators fn next(&mut self) -> Option; + fn advance_by(&mut self, n: usize) -> Result<(), NonZero>; fn nth(&mut self, n: usize) -> Option; fn try_fold(&mut self, acc: Acc, fold: Fold) -> R where @@ -301,6 +307,22 @@ where and_then_or_clear(&mut self.iter, Iterator::next) } + #[inline] + default fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + let Some(iter) = &mut self.iter else { + return match NonZero::new(n) { + Some(n) => Err(n), + None => Ok(()), + }; + }; + + let res = iter.advance_by(n); + if res.is_err() { + self.iter = None; + } + res + } + #[inline] default fn nth(&mut self, n: usize) -> Option { and_then_or_clear(&mut self.iter, |iter| iter.nth(n)) @@ -381,6 +403,17 @@ where self.iter.as_mut()?.next() } + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), NonZero> { + match &mut self.iter { + Some(iter) => iter.advance_by(n), + None => match NonZero::new(n) { + Some(n) => Err(n), + None => Ok(()), + }, + } + } + #[inline] fn nth(&mut self, n: usize) -> Option { self.iter.as_mut()?.nth(n) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 1b393e6c928e8..41f4b837efaea 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -157,6 +157,13 @@ //! the allocation), `base + o` will not wrap around the address space (in //! other words, will not overflow `usize`) //! +//! Allocations typically have a fixed size that cannot change. However, allocations created by +//! directly invoking page table operations of the operating system, e.g. via `mmap`, are allowed to +//! grow by adding more pages to them at the end. Unmapping parts of an allocation (i.e., shrinking +//! it or punching holes into it) is currently not supported. Allocations created via +//! "compiler-recognized" operations, such as `std::alloc` methods or `libc::malloc`, can never +//! change their size, even if they use `mmap` under the hood. +//! //! [`null()`]: null //! //! # Provenance diff --git a/library/std/src/io/buffered/mod.rs b/library/std/src/io/buffered/mod.rs deleted file mode 100644 index 1d09ff7d8dc1c..0000000000000 --- a/library/std/src/io/buffered/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -//! Buffering wrappers for I/O traits - -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/copy.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/cursor.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/impls.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 203572c9067b6..c0ed06d5311bc 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -294,9 +294,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -#[cfg(test)] -mod tests; - use alloc_crate::io::OsFunctions; #[unstable(feature = "raw_os_error_ty", issue = "107792")] pub use alloc_crate::io::RawOsError; @@ -344,12 +341,7 @@ pub(crate) use self::stdio::{attempt_print_to_stderr, cleanup}; #[doc(no_inline, hidden)] pub use self::stdio::{set_output_capture, try_set_output_capture}; -mod buffered; -mod copy; -mod cursor; mod error; -mod impls; mod pipe; pub mod prelude; mod stdio; -mod util; diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs deleted file mode 100644 index 87c2771955a9d..0000000000000 --- a/library/std/src/io/util.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(test)] -mod tests; diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-reg.md b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md index 095b541da6e46..db72c44a2dc92 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-reg.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-reg.md @@ -19,9 +19,6 @@ This tracks support for additional registers in architectures where inline assem | Architecture | Register class | Target feature | Allowed types | | ------------ | -------------- | -------------- | ------------- | -| x86 | `xmm_reg` | `sse` | `i128` | -| x86 | `ymm_reg` | `avx` | `i128` | -| x86 | `zmm_reg` | `avx512f` | `i128` | | LoongArch | `vreg` | `lsx` | `f32`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | | LoongArch | `xreg` | `lasx` | `f32`, `f64`,
`i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2`,
`i8x32`, `i16x16`, `i32x8`, `i64x4`, `f32x8`, `f64x4` | diff --git a/tests/rustdoc-html/jump-to-def/non-local-method.rs b/tests/rustdoc-html/jump-to-def/non-local-method.rs index e785ab8d204f9..db85d31bf656c 100644 --- a/tests/rustdoc-html/jump-to-def/non-local-method.rs +++ b/tests/rustdoc-html/jump-to-def/non-local-method.rs @@ -16,7 +16,7 @@ use std::cmp::Ordering; use std::marker::PhantomData; pub fn bar2(readable: T) { - //@ has - '//a[@href="{{channel}}/alloc/io/read/trait.Read.html#tymethod.read"]' 'read' + //@ has - '//a[@href="{{channel}}/alloc/io/read/trait.Read.html#method.read"]' 'read' let _ = readable.read(&mut []); } diff --git a/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr b/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr index fe2a53aec5d48..a03791b9222cc 100644 --- a/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr +++ b/tests/ui/asm/x86_64/bad-reg.experimental_reg.stderr @@ -1,5 +1,5 @@ error: invalid register class `foo`: unknown register class - --> $DIR/bad-reg.rs:20:20 + --> $DIR/bad-reg.rs:19:20 | LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | asm!("{}", in(foo) foo); = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, and `tmm_reg` error: invalid register `foo`: unknown register - --> $DIR/bad-reg.rs:22:18 + --> $DIR/bad-reg.rs:21:18 | LL | asm!("", in("foo") foo); | ^^^^^^^^^^^^^ error: invalid asm template modifier `z` for this register class - --> $DIR/bad-reg.rs:24:15 + --> $DIR/bad-reg.rs:23:15 | LL | asm!("{:z}", in(reg) foo); | ^^^^ ----------- argument @@ -23,7 +23,7 @@ LL | asm!("{:z}", in(reg) foo); = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, and `r` error: invalid asm template modifier `r` for this register class - --> $DIR/bad-reg.rs:26:15 + --> $DIR/bad-reg.rs:25:15 | LL | asm!("{:r}", in(xmm_reg) foo); | ^^^^ --------------- argument @@ -33,7 +33,7 @@ LL | asm!("{:r}", in(xmm_reg) foo); = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, and `z` error: asm template modifiers are not allowed for `const` arguments - --> $DIR/bad-reg.rs:28:15 + --> $DIR/bad-reg.rs:27:15 | LL | asm!("{:a}", const 0); | ^^^^ ------- argument @@ -41,7 +41,7 @@ LL | asm!("{:a}", const 0); | template modifier error: asm template modifiers are not allowed for `sym` arguments - --> $DIR/bad-reg.rs:30:15 + --> $DIR/bad-reg.rs:29:15 | LL | asm!("{:a}", sym main); | ^^^^ -------- argument @@ -49,67 +49,67 @@ LL | asm!("{:a}", sym main); | template modifier error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:31:18 | LL | asm!("", in("ebp") foo); | ^^^^^^^^^^^^^ error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:34:18 + --> $DIR/bad-reg.rs:33:18 | LL | asm!("", in("rsp") foo); | ^^^^^^^^^^^^^ error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:36:18 + --> $DIR/bad-reg.rs:35:18 | LL | asm!("", in("ip") foo); | ^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:43:18 + --> $DIR/bad-reg.rs:42:18 | LL | asm!("", in("st(2)") foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:46:18 + --> $DIR/bad-reg.rs:45:18 | LL | asm!("", in("mm0") foo); | ^^^^^^^^^^^^^ error: register class `kreg0` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:49:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", in("k0") foo); | ^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:54:20 + --> $DIR/bad-reg.rs:53:20 | LL | asm!("{}", in(x87_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:57:20 + --> $DIR/bad-reg.rs:56:20 | LL | asm!("{}", in(mmx_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:60:20 + --> $DIR/bad-reg.rs:59:20 | LL | asm!("{}", out(x87_reg) _); | ^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:62:20 + --> $DIR/bad-reg.rs:61:20 | LL | asm!("{}", out(mmx_reg) _); | ^^^^^^^^^^^^^^ error: register `al` conflicts with register `eax` - --> $DIR/bad-reg.rs:68:33 + --> $DIR/bad-reg.rs:67:33 | LL | asm!("", in("eax") foo, in("al") bar); | ------------- ^^^^^^^^^^^^ register `al` @@ -117,7 +117,7 @@ LL | asm!("", in("eax") foo, in("al") bar); | register `eax` error: register `rax` conflicts with register `rax` - --> $DIR/bad-reg.rs:71:33 + --> $DIR/bad-reg.rs:70:33 | LL | asm!("", in("rax") foo, out("rax") bar); | ------------- ^^^^^^^^^^^^^^ register `rax` @@ -125,13 +125,13 @@ LL | asm!("", in("rax") foo, out("rax") bar); | register `rax` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:71:18 + --> $DIR/bad-reg.rs:70:18 | LL | asm!("", in("rax") foo, out("rax") bar); | ^^^^^^^^^^^^^ error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:76:34 + --> $DIR/bad-reg.rs:75:34 | LL | asm!("", in("xmm0") foo, in("ymm0") bar); | -------------- ^^^^^^^^^^^^^^ register `ymm0` @@ -139,7 +139,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar); | register `xmm0` error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:78:34 + --> $DIR/bad-reg.rs:77:34 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | -------------- ^^^^^^^^^^^^^^^ register `ymm0` @@ -147,25 +147,25 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar); | register `xmm0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:78:18 + --> $DIR/bad-reg.rs:77:18 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | ^^^^^^^^^^^^^^ error: cannot use register `bl`: rbx is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:38:18 + --> $DIR/bad-reg.rs:37:18 | LL | asm!("", in("bl") foo); | ^^^^^^^^^^^^ error: cannot use register `bh`: rbx is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:40:18 + --> $DIR/bad-reg.rs:39:18 | LL | asm!("", in("bh") foo); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:43:30 + --> $DIR/bad-reg.rs:42:30 | LL | asm!("", in("st(2)") foo); | ^^^ @@ -173,7 +173,7 @@ LL | asm!("", in("st(2)") foo); = note: register class `x87_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:46:28 + --> $DIR/bad-reg.rs:45:28 | LL | asm!("", in("mm0") foo); | ^^^ @@ -181,7 +181,7 @@ LL | asm!("", in("mm0") foo); = note: register class `mmx_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:49:27 + --> $DIR/bad-reg.rs:48:27 | LL | asm!("", in("k0") foo); | ^^^ @@ -189,7 +189,7 @@ LL | asm!("", in("k0") foo); = note: register class `kreg0` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:54:32 + --> $DIR/bad-reg.rs:53:32 | LL | asm!("{}", in(x87_reg) foo); | ^^^ @@ -197,7 +197,7 @@ LL | asm!("{}", in(x87_reg) foo); = note: register class `x87_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:57:32 + --> $DIR/bad-reg.rs:56:32 | LL | asm!("{}", in(mmx_reg) foo); | ^^^ @@ -205,7 +205,7 @@ LL | asm!("{}", in(mmx_reg) foo); = note: register class `mmx_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:68:42 + --> $DIR/bad-reg.rs:67:42 | LL | asm!("", in("eax") foo, in("al") bar); | ^^^ @@ -213,7 +213,7 @@ LL | asm!("", in("eax") foo, in("al") bar); = note: register class `reg_byte` supports these types: i8 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:73:27 + --> $DIR/bad-reg.rs:72:27 | LL | asm!("", in("al") foo, lateout("al") bar); | ^^^ @@ -221,7 +221,7 @@ LL | asm!("", in("al") foo, lateout("al") bar); = note: register class `reg_byte` supports these types: i8 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:73:46 + --> $DIR/bad-reg.rs:72:46 | LL | asm!("", in("al") foo, lateout("al") bar); | ^^^ diff --git a/tests/ui/asm/x86_64/bad-reg.rs b/tests/ui/asm/x86_64/bad-reg.rs index cc3def95508ff..3e9858f4d9664 100644 --- a/tests/ui/asm/x86_64/bad-reg.rs +++ b/tests/ui/asm/x86_64/bad-reg.rs @@ -3,7 +3,6 @@ //@ compile-flags: --target x86_64-unknown-linux-gnu -C target-feature=+avx2,+avx512f //@ needs-llvm-components: x86 #![cfg_attr(experimental_reg, feature(asm_experimental_reg))] - #![crate_type = "lib"] #![feature(no_core)] #![no_core] @@ -79,22 +78,16 @@ fn main() { //~^ ERROR register `ymm0` conflicts with register `xmm0` asm!("", in("xmm0") foo, lateout("ymm0") bar); - // Passing u128/i128 is currently experimental. + // Use 128-bit integers with vector registers. let mut xmmword = 0u128; - asm!("/* {:x} */", in(xmm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable - asm!("/* {:x} */", out(xmm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable + asm!("/* {:x} */", in(xmm_reg) xmmword); + asm!("/* {:x} */", out(xmm_reg) xmmword); - asm!("/* {:y} */", in(ymm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable - asm!("/* {:y} */", out(ymm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable + asm!("/* {:y} */", in(ymm_reg) xmmword); + asm!("/* {:y} */", out(ymm_reg) xmmword); - asm!("/* {:z} */", in(zmm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable - asm!("/* {:z} */", out(zmm_reg) xmmword); // requires asm_experimental_reg - //[stable]~^ ERROR type `u128` cannot be used with this register class in stable + asm!("/* {:z} */", in(zmm_reg) xmmword); + asm!("/* {:z} */", out(zmm_reg) xmmword); } } diff --git a/tests/ui/asm/x86_64/bad-reg.stable.stderr b/tests/ui/asm/x86_64/bad-reg.stable.stderr index d8a37933065e1..a03791b9222cc 100644 --- a/tests/ui/asm/x86_64/bad-reg.stable.stderr +++ b/tests/ui/asm/x86_64/bad-reg.stable.stderr @@ -1,5 +1,5 @@ error: invalid register class `foo`: unknown register class - --> $DIR/bad-reg.rs:20:20 + --> $DIR/bad-reg.rs:19:20 | LL | asm!("{}", in(foo) foo); | ^^^^^^^^^^^ @@ -7,13 +7,13 @@ LL | asm!("{}", in(foo) foo); = note: the following register classes are supported on this target: `reg`, `reg_abcd`, `reg_byte`, `xmm_reg`, `ymm_reg`, `zmm_reg`, `kreg`, `kreg0`, `mmx_reg`, `x87_reg`, and `tmm_reg` error: invalid register `foo`: unknown register - --> $DIR/bad-reg.rs:22:18 + --> $DIR/bad-reg.rs:21:18 | LL | asm!("", in("foo") foo); | ^^^^^^^^^^^^^ error: invalid asm template modifier `z` for this register class - --> $DIR/bad-reg.rs:24:15 + --> $DIR/bad-reg.rs:23:15 | LL | asm!("{:z}", in(reg) foo); | ^^^^ ----------- argument @@ -23,7 +23,7 @@ LL | asm!("{:z}", in(reg) foo); = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, and `r` error: invalid asm template modifier `r` for this register class - --> $DIR/bad-reg.rs:26:15 + --> $DIR/bad-reg.rs:25:15 | LL | asm!("{:r}", in(xmm_reg) foo); | ^^^^ --------------- argument @@ -33,7 +33,7 @@ LL | asm!("{:r}", in(xmm_reg) foo); = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, and `z` error: asm template modifiers are not allowed for `const` arguments - --> $DIR/bad-reg.rs:28:15 + --> $DIR/bad-reg.rs:27:15 | LL | asm!("{:a}", const 0); | ^^^^ ------- argument @@ -41,7 +41,7 @@ LL | asm!("{:a}", const 0); | template modifier error: asm template modifiers are not allowed for `sym` arguments - --> $DIR/bad-reg.rs:30:15 + --> $DIR/bad-reg.rs:29:15 | LL | asm!("{:a}", sym main); | ^^^^ -------- argument @@ -49,67 +49,67 @@ LL | asm!("{:a}", sym main); | template modifier error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:31:18 | LL | asm!("", in("ebp") foo); | ^^^^^^^^^^^^^ error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:34:18 + --> $DIR/bad-reg.rs:33:18 | LL | asm!("", in("rsp") foo); | ^^^^^^^^^^^^^ error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:36:18 + --> $DIR/bad-reg.rs:35:18 | LL | asm!("", in("ip") foo); | ^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:43:18 + --> $DIR/bad-reg.rs:42:18 | LL | asm!("", in("st(2)") foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:46:18 + --> $DIR/bad-reg.rs:45:18 | LL | asm!("", in("mm0") foo); | ^^^^^^^^^^^^^ error: register class `kreg0` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:49:18 + --> $DIR/bad-reg.rs:48:18 | LL | asm!("", in("k0") foo); | ^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:54:20 + --> $DIR/bad-reg.rs:53:20 | LL | asm!("{}", in(x87_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:57:20 + --> $DIR/bad-reg.rs:56:20 | LL | asm!("{}", in(mmx_reg) foo); | ^^^^^^^^^^^^^^^ error: register class `x87_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:60:20 + --> $DIR/bad-reg.rs:59:20 | LL | asm!("{}", out(x87_reg) _); | ^^^^^^^^^^^^^^ error: register class `mmx_reg` can only be used as a clobber, not as an input or output - --> $DIR/bad-reg.rs:62:20 + --> $DIR/bad-reg.rs:61:20 | LL | asm!("{}", out(mmx_reg) _); | ^^^^^^^^^^^^^^ error: register `al` conflicts with register `eax` - --> $DIR/bad-reg.rs:68:33 + --> $DIR/bad-reg.rs:67:33 | LL | asm!("", in("eax") foo, in("al") bar); | ------------- ^^^^^^^^^^^^ register `al` @@ -117,7 +117,7 @@ LL | asm!("", in("eax") foo, in("al") bar); | register `eax` error: register `rax` conflicts with register `rax` - --> $DIR/bad-reg.rs:71:33 + --> $DIR/bad-reg.rs:70:33 | LL | asm!("", in("rax") foo, out("rax") bar); | ------------- ^^^^^^^^^^^^^^ register `rax` @@ -125,13 +125,13 @@ LL | asm!("", in("rax") foo, out("rax") bar); | register `rax` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:71:18 + --> $DIR/bad-reg.rs:70:18 | LL | asm!("", in("rax") foo, out("rax") bar); | ^^^^^^^^^^^^^ error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:76:34 + --> $DIR/bad-reg.rs:75:34 | LL | asm!("", in("xmm0") foo, in("ymm0") bar); | -------------- ^^^^^^^^^^^^^^ register `ymm0` @@ -139,7 +139,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar); | register `xmm0` error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:78:34 + --> $DIR/bad-reg.rs:77:34 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | -------------- ^^^^^^^^^^^^^^^ register `ymm0` @@ -147,25 +147,25 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar); | register `xmm0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:78:18 + --> $DIR/bad-reg.rs:77:18 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | ^^^^^^^^^^^^^^ error: cannot use register `bl`: rbx is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:38:18 + --> $DIR/bad-reg.rs:37:18 | LL | asm!("", in("bl") foo); | ^^^^^^^^^^^^ error: cannot use register `bh`: rbx is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:40:18 + --> $DIR/bad-reg.rs:39:18 | LL | asm!("", in("bh") foo); | ^^^^^^^^^^^^ error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:43:30 + --> $DIR/bad-reg.rs:42:30 | LL | asm!("", in("st(2)") foo); | ^^^ @@ -173,7 +173,7 @@ LL | asm!("", in("st(2)") foo); = note: register class `x87_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:46:28 + --> $DIR/bad-reg.rs:45:28 | LL | asm!("", in("mm0") foo); | ^^^ @@ -181,7 +181,7 @@ LL | asm!("", in("mm0") foo); = note: register class `mmx_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:49:27 + --> $DIR/bad-reg.rs:48:27 | LL | asm!("", in("k0") foo); | ^^^ @@ -189,7 +189,7 @@ LL | asm!("", in("k0") foo); = note: register class `kreg0` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:54:32 + --> $DIR/bad-reg.rs:53:32 | LL | asm!("{}", in(x87_reg) foo); | ^^^ @@ -197,7 +197,7 @@ LL | asm!("{}", in(x87_reg) foo); = note: register class `x87_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:57:32 + --> $DIR/bad-reg.rs:56:32 | LL | asm!("{}", in(mmx_reg) foo); | ^^^ @@ -205,7 +205,7 @@ LL | asm!("{}", in(mmx_reg) foo); = note: register class `mmx_reg` supports these types: error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:68:42 + --> $DIR/bad-reg.rs:67:42 | LL | asm!("", in("eax") foo, in("al") bar); | ^^^ @@ -213,7 +213,7 @@ LL | asm!("", in("eax") foo, in("al") bar); = note: register class `reg_byte` supports these types: i8 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:73:27 + --> $DIR/bad-reg.rs:72:27 | LL | asm!("", in("al") foo, lateout("al") bar); | ^^^ @@ -221,73 +221,12 @@ LL | asm!("", in("al") foo, lateout("al") bar); = note: register class `reg_byte` supports these types: i8 error: type `i32` cannot be used with this register class - --> $DIR/bad-reg.rs:73:46 + --> $DIR/bad-reg.rs:72:46 | LL | asm!("", in("al") foo, lateout("al") bar); | ^^^ | = note: register class `reg_byte` supports these types: i8 -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:85:40 - | -LL | asm!("/* {:x} */", in(xmm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:87:41 - | -LL | asm!("/* {:x} */", out(xmm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:90:40 - | -LL | asm!("/* {:y} */", in(ymm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:92:41 - | -LL | asm!("/* {:y} */", out(ymm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:95:40 - | -LL | asm!("/* {:z} */", in(zmm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/bad-reg.rs:97:41 - | -LL | asm!("/* {:z} */", out(zmm_reg) xmmword); // requires asm_experimental_reg - | ^^^^^^^ - | - = note: see issue #133416 for more information - = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable - = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date - -error: aborting due to 36 previous errors +error: aborting due to 30 previous errors -For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/asm/x86_64/type-check-3.stderr b/tests/ui/asm/x86_64/type-check-3.stderr index 5a7b349413e45..ea9a3955e7078 100644 --- a/tests/ui/asm/x86_64/type-check-3.stderr +++ b/tests/ui/asm/x86_64/type-check-3.stderr @@ -28,7 +28,7 @@ error: type `u8` cannot be used with this register class LL | asm!("{}", in(xmm_reg) 0u8); | ^^^ | - = note: register class `xmm_reg` supports these types: i32, i64, f16, f32, f64, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 + = note: register class `xmm_reg` supports these types: i32, i64, i128, f16, f32, f64, f128, i8x16, i16x8, i32x4, i64x2, f16x8, f32x4, f64x2 error: `avx512bw` target feature is not enabled --> $DIR/type-check-3.rs:27:29 diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs index bfc79ae8db663..0d2c4fe2b67c3 100644 --- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs +++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.rs @@ -1,16 +1,27 @@ //@ add-minicore -//@ compile-flags: --target x86_64-unknown-linux-gnu -//@ needs-llvm-components: x86 +//@ compile-flags: --target loongarch64-unknown-none +//@ needs-llvm-components: loongarch //@ ignore-backends: gcc -#![feature(no_core, lang_items, rustc_attrs)] +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] #![crate_type = "rlib"] #![no_core] +#![allow(non_camel_case_types)] extern crate minicore; use minicore::*; -unsafe fn main() { - asm!("{:x}", in(xmm_reg) 0u128); - //~^ ERROR type `u128` cannot be used with this register class in stable +#[repr(simd)] +pub struct i8x16([i8; 16]); + +impl Copy for i8x16 {} + +unsafe fn main(x: i8x16) -> i8x16 { + let y; + asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + //~^ ERROR register class `vreg` can only be used as a clobber in stable + //~| ERROR register class `vreg` can only be used as a clobber in stable + //~| ERROR type `i8x16` cannot be used with this register class in stable + //~| ERROR type `i8x16` cannot be used with this register class in stable + y } diff --git a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr index 4042ee7029b53..fb54438ef589e 100644 --- a/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr +++ b/tests/ui/feature-gates/feature-gate-asm_experimental_reg.stderr @@ -1,13 +1,43 @@ -error[E0658]: type `u128` cannot be used with this register class in stable - --> $DIR/feature-gate-asm_experimental_reg.rs:14:30 +error[E0658]: register class `vreg` can only be used as a clobber in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:21:41 | -LL | asm!("{:x}", in(xmm_reg) 0u128); - | ^^^^^ +LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + | ^^^^^^^^^^^ | = note: see issue #133416 for more information = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 1 previous error +error[E0658]: register class `vreg` can only be used as a clobber in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:21:54 + | +LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + | ^^^^^^^^^^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: type `i8x16` cannot be used with this register class in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:21:51 + | +LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + | ^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error[E0658]: type `i8x16` cannot be used with this register class in stable + --> $DIR/feature-gate-asm_experimental_reg.rs:21:63 + | +LL | asm!("xvadd.h {1:u}, {0:u}, {0:u}", out(vreg) y, in(vreg) x); + | ^ + | + = note: see issue #133416 for more information + = help: add `#![feature(asm_experimental_reg)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-nesting.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-nesting.rs new file mode 100644 index 0000000000000..927892c19a063 --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep-with-nesting.rs @@ -0,0 +1,14 @@ +#![crate_type = "lib"] + +extern crate transitive_dep; + +mod private { + pub mod inner { + pub use crate::transitive_dep::Struct; + } +} + +#[doc(hidden)] +pub mod __private { + pub use crate::private::*; +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep.rs new file mode 100644 index 0000000000000..cb37184c0ba85 --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/direct-dep.rs @@ -0,0 +1,12 @@ +#![crate_type = "lib"] + +extern crate transitive_dep; + +mod private { + pub use crate::transitive_dep::Struct; +} + +#[doc(hidden)] +pub mod __private { + pub use crate::private::*; +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/transitive-dep.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/transitive-dep.rs new file mode 100644 index 0000000000000..a2c189e59d80e --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/auxiliary/transitive-dep.rs @@ -0,0 +1,3 @@ +#![crate_type = "lib"] + +pub struct Struct; diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.rs new file mode 100644 index 0000000000000..c8d04a9f049f1 --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.rs @@ -0,0 +1,16 @@ +//@ aux-build: transitive-dep.rs +//@ aux-build: direct-dep-with-nesting.rs + +extern crate direct_dep_with_nesting as direct_dep; + +struct Struct; +//~^ NOTE `Struct` is defined in the current crate + +fn main() { + let _: direct_dep::__private::inner::Struct = Struct; + //~^ ERROR mismatched types + //~| NOTE expected `direct_dep::__private::inner::Struct`, found `Struct` + //~| NOTE expected due to this + //~| NOTE `Struct` and `direct_dep::__private::inner::Struct` have similar names, but are actually distinct types + //~| NOTE `direct_dep::__private::inner::Struct` is defined in crate `transitive_dep` +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.stderr b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.stderr new file mode 100644 index 0000000000000..5ab50bebc294c --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-nested-transitive-dep-item.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/hidden-reexport-of-nested-transitive-dep-item.rs:10:51 + | +LL | let _: direct_dep::__private::inner::Struct = Struct; + | ------------------------------------ ^^^^^^ expected `direct_dep::__private::inner::Struct`, found `Struct` + | | + | expected due to this + | + = note: `Struct` and `direct_dep::__private::inner::Struct` have similar names, but are actually distinct types +note: `Struct` is defined in the current crate + --> $DIR/hidden-reexport-of-nested-transitive-dep-item.rs:6:1 + | +LL | struct Struct; + | ^^^^^^^^^^^^^ +note: `direct_dep::__private::inner::Struct` is defined in crate `transitive_dep` + --> $DIR/auxiliary/transitive-dep.rs:3:1 + | +LL | pub struct Struct; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.rs b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.rs new file mode 100644 index 0000000000000..e92b3afaf4e6f --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.rs @@ -0,0 +1,16 @@ +//@ aux-build: transitive-dep.rs +//@ aux-build: direct-dep.rs + +extern crate direct_dep; + +struct Struct; +//~^ NOTE `Struct` is defined in the current crate + +fn main() { + let _: direct_dep::__private::Struct = Struct; + //~^ ERROR mismatched types + //~| NOTE expected `direct_dep::__private::Struct`, found `Struct` + //~| NOTE expected due to this + //~| NOTE `Struct` and `direct_dep::__private::Struct` have similar names, but are actually distinct types + //~| NOTE `direct_dep::__private::Struct` is defined in crate `transitive_dep` +} diff --git a/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.stderr b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.stderr new file mode 100644 index 0000000000000..3dd899eb36f0c --- /dev/null +++ b/tests/ui/suggestions/suggest-path-through-direct-dep-crate/hidden-reexport-of-transitive-dep-item.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/hidden-reexport-of-transitive-dep-item.rs:10:44 + | +LL | let _: direct_dep::__private::Struct = Struct; + | ----------------------------- ^^^^^^ expected `direct_dep::__private::Struct`, found `Struct` + | | + | expected due to this + | + = note: `Struct` and `direct_dep::__private::Struct` have similar names, but are actually distinct types +note: `Struct` is defined in the current crate + --> $DIR/hidden-reexport-of-transitive-dep-item.rs:6:1 + | +LL | struct Struct; + | ^^^^^^^^^^^^^ +note: `direct_dep::__private::Struct` is defined in crate `transitive_dep` + --> $DIR/auxiliary/transitive-dep.rs:3:1 + | +LL | pub struct Struct; + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`.