diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index aff98c63bcb41..def0cb74d295b 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -120,7 +120,7 @@ fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec pos += shebang_len; } - for token in rustc_lexer::tokenize(&text[pos..]) { + for token in rustc_lexer::tokenize(&text[pos..], rustc_lexer::FrontmatterAllowed::Yes) { let token_text = &text[pos..pos + token.len as usize]; match token.kind { rustc_lexer::TokenKind::Whitespace => { @@ -171,6 +171,14 @@ fn gather_comments(sm: &SourceMap, path: FileName, src: String) -> Vec }) } } + rustc_lexer::TokenKind::Frontmatter { .. } => { + code_to_the_left = false; + comments.push(Comment { + style: CommentStyle::Isolated, + lines: vec![token_text.to_string()], + pos: start_bpos + BytePos(pos as u32), + }); + } _ => { code_to_the_left = true; } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index cbbb0196890fd..bf3b1e73b94c8 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -207,9 +207,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { { // These cases are all UB to actually hit, so don't emit code for them. // (The size mismatches are reachable via `transmute_unchecked`.) - // We can't use unreachable because that's a terminator, and we - // need something that can be in the middle of a basic block. - bx.assume(bx.cx().const_bool(false)) + bx.unreachable_nonterminator(); } else { // Since in this path we have a place anyway, we can store or copy to it, // making sure we use the destination place's alignment even if the @@ -236,14 +234,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { || operand.layout.is_uninhabited() || cast.is_uninhabited() { - if !operand.layout.is_uninhabited() { - // Since this is known statically and the input could have existed - // without already having hit UB, might as well trap for it. - bx.abort(); - } + bx.unreachable_nonterminator(); - // Because this transmute is UB, return something easy to generate, - // since it's fine that later uses of the value are probably UB. + // We still need to return a value of the appropriate type, but + // it's already UB so do the easiest thing available. return OperandValue::poison(bx, cast); } diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index 9d367748c2a8a..0f1358ee50850 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -136,6 +136,16 @@ pub trait BuilderMethods<'a, 'tcx>: ) -> Self::Value; fn unreachable(&mut self); + /// Like [`Self::unreachable`], but for use in the middle of a basic block. + fn unreachable_nonterminator(&mut self) { + // This is the preferred LLVM incantation for this per + // https://llvm.org/docs/Frontend/PerformanceTips.html#other-things-to-consider + // Other backends may override if they have a better way. + let const_true = self.cx().const_bool(true); + let poison_ptr = self.const_poison(self.cx().type_ptr()); + self.store(const_true, poison_ptr, Align::ONE); + } + fn add(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fadd(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; fn fadd_fast(&mut self, lhs: Self::Value, rhs: Self::Value) -> Self::Value; diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 510f37f37e2ac..95400ac2ca3b0 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2446,17 +2446,22 @@ impl HumanEmitter { | DisplaySuggestion::Underline => row_num - 1, DisplaySuggestion::None => row_num, }; - self.draw_col_separator_end(&mut buffer, row, max_line_num_len + 1); + if other_suggestions > 0 { + self.draw_col_separator_no_space(&mut buffer, row, max_line_num_len + 1); + } else { + self.draw_col_separator_end(&mut buffer, row, max_line_num_len + 1); + } row_num = row + 1; } } if other_suggestions > 0 { + self.draw_note_separator(&mut buffer, row_num, max_line_num_len + 1, false); let msg = format!( "and {} other candidate{}", other_suggestions, pluralize!(other_suggestions) ); - buffer.puts(row_num, max_line_num_len + 3, &msg, Style::NoStyle); + buffer.append(row_num, &msg, Style::NoStyle); } emit_to_destination(&buffer.render(), level, &mut self.dst, self.short_message)?; diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index e30dbe80248d4..e80196ed5679d 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -273,14 +273,15 @@ pub fn strip_shebang(input: &str) -> Option { if let Some(input_tail) = input.strip_prefix("#!") { // Ok, this is a shebang but if the next non-whitespace token is `[`, // then it may be valid Rust code, so consider it Rust code. - let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| { - !matches!( - tok, - TokenKind::Whitespace - | TokenKind::LineComment { doc_style: None } - | TokenKind::BlockComment { doc_style: None, .. } - ) - }); + let next_non_whitespace_token = + tokenize(input_tail, FrontmatterAllowed::No).map(|tok| tok.kind).find(|tok| { + !matches!( + tok, + TokenKind::Whitespace + | TokenKind::LineComment { doc_style: None } + | TokenKind::BlockComment { doc_style: None, .. } + ) + }); if next_non_whitespace_token != Some(TokenKind::OpenBracket) { // No other choice than to consider this a shebang. return Some(2 + input_tail.lines().next().unwrap_or_default().len()); @@ -303,8 +304,16 @@ pub fn validate_raw_str(input: &str, prefix_len: u32) -> Result<(), RawStrError> } /// Creates an iterator that produces tokens from the input string. -pub fn tokenize(input: &str) -> impl Iterator { - let mut cursor = Cursor::new(input, FrontmatterAllowed::No); +/// +/// When parsing a full Rust document, +/// first [`strip_shebang`] and then allow frontmatters with [`FrontmatterAllowed::Yes`]. +/// +/// When tokenizing a slice of a document, be sure to disallow frontmatters with [`FrontmatterAllowed::No`] +pub fn tokenize( + input: &str, + frontmatter_allowed: FrontmatterAllowed, +) -> impl Iterator { + let mut cursor = Cursor::new(input, frontmatter_allowed); std::iter::from_fn(move || { let token = cursor.advance_token(); if token.kind != TokenKind::Eof { Some(token) } else { None } diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs index fc8d9b9d57bc4..a7357ba38c8e4 100644 --- a/compiler/rustc_lexer/src/tests.rs +++ b/compiler/rustc_lexer/src/tests.rs @@ -124,8 +124,9 @@ fn test_valid_shebang() { assert_eq!(strip_shebang(input), None); } -fn check_lexing(src: &str, expect: Expect) { - let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect(); +fn check_lexing(src: &str, frontmatter_allowed: FrontmatterAllowed, expect: Expect) { + let actual: String = + tokenize(src, frontmatter_allowed).map(|token| format!("{:?}\n", token)).collect(); expect.assert_eq(&actual) } @@ -133,6 +134,7 @@ fn check_lexing(src: &str, expect: Expect) { fn smoke_test() { check_lexing( "/* my source file */ fn main() { println!(\"zebra\"); }\n", + FrontmatterAllowed::No, expect![[r#" Token { kind: BlockComment { doc_style: None, terminated: true }, len: 20 } Token { kind: Whitespace, len: 1 } @@ -171,6 +173,7 @@ fn comment_flavors() { /** outer doc block */ /*! inner doc block */ ", + FrontmatterAllowed::No, expect![[r#" Token { kind: Whitespace, len: 1 } Token { kind: LineComment { doc_style: None }, len: 7 } @@ -199,6 +202,7 @@ fn comment_flavors() { fn nested_block_comments() { check_lexing( "/* /* */ */'a'", + FrontmatterAllowed::No, expect![[r#" Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } @@ -210,6 +214,7 @@ fn nested_block_comments() { fn characters() { check_lexing( "'a' ' ' '\\n'", + FrontmatterAllowed::No, expect![[r#" Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } Token { kind: Whitespace, len: 1 } @@ -224,6 +229,7 @@ fn characters() { fn lifetime() { check_lexing( "'abc", + FrontmatterAllowed::No, expect![[r#" Token { kind: Lifetime { starts_with_number: false }, len: 4 } "#]], @@ -234,6 +240,7 @@ fn lifetime() { fn raw_string() { check_lexing( "r###\"\"#a\\b\x00c\"\"###", + FrontmatterAllowed::No, expect![[r#" Token { kind: Literal { kind: RawStr { n_hashes: Some(3) }, suffix_start: 17 }, len: 17 } "#]], @@ -257,6 +264,7 @@ b"a" r###"raw"###suffix br###"raw"###suffix "####, + FrontmatterAllowed::No, expect![[r#" Token { kind: Whitespace, len: 1 } Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } @@ -286,3 +294,78 @@ br###"raw"###suffix "#]], ) } + +#[test] +fn frontmatter_allowed() { + check_lexing( + r#" +---cargo +[dependencies] +clap = "4" +--- + +fn main() {} +"#, + FrontmatterAllowed::Yes, + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: Frontmatter { has_invalid_preceding_whitespace: false, invalid_infostring: false }, len: 38 } + Token { kind: Whitespace, len: 2 } + Token { kind: Ident, len: 2 } + Token { kind: Whitespace, len: 1 } + Token { kind: Ident, len: 4 } + Token { kind: OpenParen, len: 1 } + Token { kind: CloseParen, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: OpenBrace, len: 1 } + Token { kind: CloseBrace, len: 1 } + Token { kind: Whitespace, len: 1 } + "#]], + ) +} + +#[test] +fn frontmatter_disallowed() { + check_lexing( + r#" +---cargo +[dependencies] +clap = "4" +--- + +fn main() {} +"#, + FrontmatterAllowed::No, + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: Minus, len: 1 } + Token { kind: Minus, len: 1 } + Token { kind: Minus, len: 1 } + Token { kind: Ident, len: 5 } + Token { kind: Whitespace, len: 1 } + Token { kind: OpenBracket, len: 1 } + Token { kind: Ident, len: 12 } + Token { kind: CloseBracket, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: Ident, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: Eq, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Str { terminated: true }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Minus, len: 1 } + Token { kind: Minus, len: 1 } + Token { kind: Minus, len: 1 } + Token { kind: Whitespace, len: 2 } + Token { kind: Ident, len: 2 } + Token { kind: Whitespace, len: 1 } + Token { kind: Ident, len: 4 } + Token { kind: OpenParen, len: 1 } + Token { kind: CloseParen, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: OpenBrace, len: 1 } + Token { kind: CloseBrace, len: 1 } + Token { kind: Whitespace, len: 1 } + "#]], + ) +} diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index a5242d60bf14d..f9c4cdd0ebe63 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -45,8 +45,11 @@ impl From for TryFromIntError { /// An error which can be returned when parsing an integer. /// -/// This error is used as the error type for the `from_str_radix()` functions -/// on the primitive integer types, such as [`i8::from_str_radix`]. +/// For example, this error is returned by the `from_str_radix()` functions +/// on the primitive integer types (such as [`i8::from_str_radix`]) +/// and is used as the error type in their [`FromStr`] implementations. +/// +/// [`FromStr`]: crate::str::FromStr /// /// # Potential causes /// diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index 466b134d8faee..76e63a69e45da 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -210,6 +210,9 @@ pub trait CommandExt: Sealed { /// intentional difference from the underlying `chroot` system call.) #[unstable(feature = "process_chroot", issue = "141298")] fn chroot>(&mut self, dir: P) -> &mut process::Command; + + #[unstable(feature = "process_setsid", issue = "105376")] + fn setsid(&mut self, setsid: bool) -> &mut process::Command; } #[stable(feature = "rust1", since = "1.0.0")] @@ -260,6 +263,11 @@ impl CommandExt for process::Command { self.as_inner_mut().chroot(dir.as_ref()); self } + + fn setsid(&mut self, setsid: bool) -> &mut process::Command { + self.as_inner_mut().setsid(setsid); + self + } } /// Unix-specific extensions to [`process::ExitStatus`] and diff --git a/library/std/src/sys/net/connection/uefi/mod.rs b/library/std/src/sys/net/connection/uefi/mod.rs index 6835ba44ee242..884cbd4ac1dc7 100644 --- a/library/std/src/sys/net/connection/uefi/mod.rs +++ b/library/std/src/sys/net/connection/uefi/mod.rs @@ -1,37 +1,54 @@ use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +use crate::sync::{Arc, Mutex}; use crate::sys::unsupported; use crate::time::Duration; mod tcp; pub(crate) mod tcp4; -pub struct TcpStream(tcp::Tcp); +pub struct TcpStream { + inner: tcp::Tcp, + read_timeout: Arc>>, + write_timeout: Arc>>, +} impl TcpStream { pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result { - tcp::Tcp::connect(addr?).map(Self) + let inner = tcp::Tcp::connect(addr?, None)?; + Ok(Self { + inner, + read_timeout: Arc::new(Mutex::new(None)), + write_timeout: Arc::new(Mutex::new(None)), + }) } - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result { - unsupported() + pub fn connect_timeout(addr: &SocketAddr, timeout: Duration) -> io::Result { + let inner = tcp::Tcp::connect(addr, Some(timeout))?; + Ok(Self { + inner, + read_timeout: Arc::new(Mutex::new(None)), + write_timeout: Arc::new(Mutex::new(None)), + }) } - pub fn set_read_timeout(&self, _: Option) -> io::Result<()> { - unsupported() + pub fn set_read_timeout(&self, t: Option) -> io::Result<()> { + self.read_timeout.set(t).unwrap(); + Ok(()) } - pub fn set_write_timeout(&self, _: Option) -> io::Result<()> { - unsupported() + pub fn set_write_timeout(&self, t: Option) -> io::Result<()> { + self.write_timeout.set(t).unwrap(); + Ok(()) } pub fn read_timeout(&self) -> io::Result> { - unsupported() + Ok(self.read_timeout.get_cloned().unwrap()) } pub fn write_timeout(&self) -> io::Result> { - unsupported() + Ok(self.write_timeout.get_cloned().unwrap()) } pub fn peek(&self, _: &mut [u8]) -> io::Result { @@ -39,7 +56,7 @@ impl TcpStream { } pub fn read(&self, buf: &mut [u8]) -> io::Result { - self.0.read(buf) + self.inner.read(buf, self.read_timeout()?) } pub fn read_buf(&self, cursor: BorrowedCursor<'_>) -> io::Result<()> { @@ -56,7 +73,7 @@ impl TcpStream { } pub fn write(&self, buf: &[u8]) -> io::Result { - self.0.write(buf) + self.inner.write(buf, self.write_timeout()?) } pub fn write_vectored(&self, buf: &[IoSlice<'_>]) -> io::Result { diff --git a/library/std/src/sys/net/connection/uefi/tcp.rs b/library/std/src/sys/net/connection/uefi/tcp.rs index 55b6dbf2490bd..1152f69446e42 100644 --- a/library/std/src/sys/net/connection/uefi/tcp.rs +++ b/library/std/src/sys/net/connection/uefi/tcp.rs @@ -1,33 +1,34 @@ use super::tcp4; use crate::io; use crate::net::SocketAddr; +use crate::time::Duration; pub(crate) enum Tcp { V4(tcp4::Tcp4), } impl Tcp { - pub(crate) fn connect(addr: &SocketAddr) -> io::Result { + pub(crate) fn connect(addr: &SocketAddr, timeout: Option) -> io::Result { match addr { SocketAddr::V4(x) => { let temp = tcp4::Tcp4::new()?; temp.configure(true, Some(x), None)?; - temp.connect()?; + temp.connect(timeout)?; Ok(Tcp::V4(temp)) } SocketAddr::V6(_) => todo!(), } } - pub(crate) fn write(&self, buf: &[u8]) -> io::Result { + pub(crate) fn write(&self, buf: &[u8], timeout: Option) -> io::Result { match self { - Self::V4(client) => client.write(buf), + Self::V4(client) => client.write(buf, timeout), } } - pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result { + pub(crate) fn read(&self, buf: &mut [u8], timeout: Option) -> io::Result { match self { - Self::V4(client) => client.read(buf), + Self::V4(client) => client.read(buf, timeout), } } } diff --git a/library/std/src/sys/net/connection/uefi/tcp4.rs b/library/std/src/sys/net/connection/uefi/tcp4.rs index af1ba2be47adb..6342718929a7d 100644 --- a/library/std/src/sys/net/connection/uefi/tcp4.rs +++ b/library/std/src/sys/net/connection/uefi/tcp4.rs @@ -6,6 +6,7 @@ use crate::net::SocketAddrV4; use crate::ptr::NonNull; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::pal::helpers; +use crate::time::{Duration, Instant}; const TYPE_OF_SERVICE: u8 = 8; const TIME_TO_LIVE: u8 = 255; @@ -66,7 +67,7 @@ impl Tcp4 { if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) } } - pub(crate) fn connect(&self) -> io::Result<()> { + pub(crate) fn connect(&self, timeout: Option) -> io::Result<()> { let evt = unsafe { self.create_evt() }?; let completion_token = tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; @@ -79,7 +80,7 @@ impl Tcp4 { return Err(io::Error::from_raw_os_error(r.as_usize())); } - self.wait_for_flag(); + unsafe { self.wait_or_cancel(timeout, &mut conn_token.completion_token) }?; if completion_token.status.is_error() { Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) @@ -88,7 +89,7 @@ impl Tcp4 { } } - pub(crate) fn write(&self, buf: &[u8]) -> io::Result { + pub(crate) fn write(&self, buf: &[u8], timeout: Option) -> io::Result { let evt = unsafe { self.create_evt() }?; let completion_token = tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; @@ -119,7 +120,7 @@ impl Tcp4 { return Err(io::Error::from_raw_os_error(r.as_usize())); } - self.wait_for_flag(); + unsafe { self.wait_or_cancel(timeout, &mut token.completion_token) }?; if completion_token.status.is_error() { Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) @@ -128,7 +129,7 @@ impl Tcp4 { } } - pub(crate) fn read(&self, buf: &mut [u8]) -> io::Result { + pub(crate) fn read(&self, buf: &mut [u8], timeout: Option) -> io::Result { let evt = unsafe { self.create_evt() }?; let completion_token = tcp4::CompletionToken { event: evt.as_ptr(), status: Status::SUCCESS }; @@ -158,7 +159,7 @@ impl Tcp4 { return Err(io::Error::from_raw_os_error(r.as_usize())); } - self.wait_for_flag(); + unsafe { self.wait_or_cancel(timeout, &mut token.completion_token) }?; if completion_token.status.is_error() { Err(io::Error::from_raw_os_error(completion_token.status.as_usize())) @@ -167,6 +168,50 @@ impl Tcp4 { } } + /// Wait for an event to finish. This is checked by an atomic boolean that is supposed to be set + /// to true in the event callback. + /// + /// Optionally, allow specifying a timeout. + /// + /// If a timeout is provided, the operation (specified by its `EFI_TCP4_COMPLETION_TOKEN`) is + /// canceled and Error of kind TimedOut is returned. + /// + /// # SAFETY + /// + /// Pointer to a valid `EFI_TCP4_COMPLETION_TOKEN` + unsafe fn wait_or_cancel( + &self, + timeout: Option, + token: *mut tcp4::CompletionToken, + ) -> io::Result<()> { + if !self.wait_for_flag(timeout) { + let _ = unsafe { self.cancel(token) }; + return Err(io::Error::new(io::ErrorKind::TimedOut, "Operation Timed out")); + } + + Ok(()) + } + + /// Abort an asynchronous connection, listen, transmission or receive request. + /// + /// If token is NULL, then all pending tokens issued by EFI_TCP4_PROTOCOL.Connect(), + /// EFI_TCP4_PROTOCOL.Accept(), EFI_TCP4_PROTOCOL.Transmit() or EFI_TCP4_PROTOCOL.Receive() are + /// aborted. + /// + /// # SAFETY + /// + /// Pointer to a valid `EFI_TCP4_COMPLETION_TOKEN` or NULL + unsafe fn cancel(&self, token: *mut tcp4::CompletionToken) -> io::Result<()> { + let protocol = self.protocol.as_ptr(); + + let r = unsafe { ((*protocol).cancel)(protocol, token) }; + if r.is_error() { + return Err(io::Error::from_raw_os_error(r.as_usize())); + } else { + Ok(()) + } + } + unsafe fn create_evt(&self) -> io::Result { self.flag.store(false, Ordering::Relaxed); helpers::OwnedEvent::new( @@ -177,10 +222,19 @@ impl Tcp4 { ) } - fn wait_for_flag(&self) { + fn wait_for_flag(&self, timeout: Option) -> bool { + let start = Instant::now(); + while !self.flag.load(Ordering::Relaxed) { let _ = self.poll(); + if let Some(t) = timeout { + if Instant::now().duration_since(start) >= t { + return false; + } + } } + + true } fn poll(&self) -> io::Result<()> { diff --git a/library/std/src/sys/process/unix/common.rs b/library/std/src/sys/process/unix/common.rs index b6777b76668d5..6219be60caf2c 100644 --- a/library/std/src/sys/process/unix/common.rs +++ b/library/std/src/sys/process/unix/common.rs @@ -98,6 +98,7 @@ pub struct Command { #[cfg(target_os = "linux")] create_pidfd: bool, pgroup: Option, + setsid: bool, } // passed back to std::process with the pipes connected to the child, if any @@ -185,6 +186,7 @@ impl Command { #[cfg(target_os = "linux")] create_pidfd: false, pgroup: None, + setsid: false, } } @@ -220,6 +222,9 @@ impl Command { self.cwd(&OsStr::new("/")); } } + pub fn setsid(&mut self, setsid: bool) { + self.setsid = setsid; + } #[cfg(target_os = "linux")] pub fn create_pidfd(&mut self, val: bool) { @@ -298,6 +303,10 @@ impl Command { pub fn get_chroot(&self) -> Option<&CStr> { self.chroot.as_deref() } + #[allow(dead_code)] + pub fn get_setsid(&self) -> bool { + self.setsid + } pub fn get_closures(&mut self) -> &mut Vec io::Result<()> + Send + Sync>> { &mut self.closures diff --git a/library/std/src/sys/process/unix/common/tests.rs b/library/std/src/sys/process/unix/common/tests.rs index e5c8dd6e341e1..5f71bf051f8a8 100644 --- a/library/std/src/sys/process/unix/common/tests.rs +++ b/library/std/src/sys/process/unix/common/tests.rs @@ -134,6 +134,64 @@ fn test_process_group_no_posix_spawn() { } } +#[test] +#[cfg_attr( + any( + // See test_process_mask + target_os = "macos", + target_arch = "arm", + target_arch = "aarch64", + target_arch = "riscv64", + ), + ignore +)] +fn test_setsid_posix_spawn() { + // Spawn a cat subprocess that's just going to hang since there is no I/O. + let mut cmd = Command::new(OsStr::new("cat")); + cmd.setsid(true); + cmd.stdin(Stdio::MakePipe); + cmd.stdout(Stdio::MakePipe); + let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); + + unsafe { + // Setsid will create a new session and process group, so check that + // we can kill the process group, which means there *is* one. + t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + + t!(cat.wait()); + } +} + +#[test] +#[cfg_attr( + any( + // See test_process_mask + target_os = "macos", + target_arch = "arm", + target_arch = "aarch64", + target_arch = "riscv64", + ), + ignore +)] +fn test_setsid_no_posix_spawn() { + let mut cmd = Command::new(OsStr::new("cat")); + cmd.setsid(true); + cmd.stdin(Stdio::MakePipe); + cmd.stdout(Stdio::MakePipe); + + unsafe { + // Same as above, create hang-y cat. This time, force using the non-posix_spawn path. + cmd.pre_exec(Box::new(|| Ok(()))); // pre_exec forces fork + exec rather than posix spawn. + let (mut cat, _pipes) = t!(cmd.spawn(Stdio::Null, true)); + + // Setsid will create a new session and process group, so check that + // we can kill the process group, which means there *is* one. + t!(cvt(libc::kill(-(cat.id() as libc::pid_t), libc::SIGINT))); + + t!(cat.wait()); + } +} + #[test] fn test_program_kind() { let vectors = &[ diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index bbd03e2b0c4e9..5d13d6da18582 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -340,6 +340,10 @@ impl Command { cvt(libc::setpgid(0, pgroup))?; } + if self.get_setsid() { + cvt(libc::setsid())?; + } + // emscripten has no signal support. #[cfg(not(target_os = "emscripten"))] { @@ -741,6 +745,16 @@ impl Command { flags |= libc::POSIX_SPAWN_SETSIGDEF; } + if self.get_setsid() { + cfg_if::cfg_if! { + if #[cfg(all(target_os = "linux", target_env = "gnu"))] { + flags |= libc::POSIX_SPAWN_SETSID; + } else { + return Ok(None); + } + } + } + cvt_nz(libc::posix_spawnattr_setflags(attrs.0.as_mut_ptr(), flags as _))?; // Make sure we synchronize access to the global `environ` resource diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 6cc4b589a7207..8906e654c972a 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -9,7 +9,7 @@ use clippy_utils::visitors::{Descend, for_each_expr}; use hir::HirId; use rustc_hir as hir; use rustc_hir::{Block, BlockCheckMode, ItemKind, Node, UnsafeSource}; -use rustc_lexer::{TokenKind, tokenize}; +use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::impl_lint_pass; use rustc_span::{BytePos, Pos, RelativeBytePos, Span, SyntaxContext}; @@ -746,7 +746,7 @@ fn text_has_safety_comment(src: &str, line_starts: &[RelativeBytePos], start_pos loop { if line.starts_with("/*") { let src = &src[line_start..line_starts.last().unwrap().to_usize()]; - let mut tokens = tokenize(src); + let mut tokens = tokenize(src, FrontmatterAllowed::No); return (src[..tokens.next().unwrap().len as usize] .to_ascii_uppercase() .contains("SAFETY:") diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs index 8f314ce7a60ce..6629a67f78bd4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs @@ -3,7 +3,7 @@ use clippy_utils::source::SpanRangeExt; use itertools::Itertools; use rustc_ast::{Crate, Expr, ExprKind, FormatArgs}; use rustc_data_structures::fx::FxHashMap; -use rustc_lexer::{TokenKind, tokenize}; +use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::{EarlyContext, EarlyLintPass}; use rustc_session::impl_lint_pass; use rustc_span::{Span, hygiene}; @@ -82,7 +82,7 @@ fn has_span_from_proc_macro(cx: &EarlyContext<'_>, args: &FormatArgs) -> bool { .all(|sp| { sp.check_source_text(cx, |src| { // text should be either `, name` or `, name =` - let mut iter = tokenize(src).filter(|t| { + let mut iter = tokenize(src, FrontmatterAllowed::No).filter(|t| { !matches!( t.kind, TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index ba0376e4d4066..25afa12e95d63 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -15,7 +15,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::{ BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, PatExpr, PatExprKind, QPath, UnOp, }; -use rustc_lexer::tokenize; +use rustc_lexer::{FrontmatterAllowed, tokenize}; use rustc_lint::LateContext; use rustc_middle::mir::ConstValue; use rustc_middle::mir::interpret::{Scalar, alloc_range}; @@ -304,9 +304,7 @@ pub fn lit_to_mir_constant<'tcx>(lit: &LitKind, ty: Option>) -> Constan match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Byte(b) => Constant::Int(u128::from(b)), - LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => { - Constant::Binary(s.as_byte_str().to_vec()) - } + LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(s.as_byte_str().to_vec()), LitKind::Char(c) => Constant::Char(c), LitKind::Int(n, _) => Constant::Int(n.get()), LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { @@ -568,9 +566,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { } else { match &lit.node { LitKind::Str(is, _) => Some(is.is_empty()), - LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => { - Some(s.as_byte_str().is_empty()) - } + LitKind::ByteStr(s, _) | LitKind::CStr(s, _) => Some(s.as_byte_str().is_empty()), _ => None, } } @@ -715,7 +711,7 @@ impl<'tcx> ConstEvalCtxt<'tcx> { && let Some(src) = src.as_str() { use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace}; - if !tokenize(src) + if !tokenize(src, FrontmatterAllowed::No) .map(|t| t.kind) .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)) .eq([OpenBrace]) diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 0ca494f16e31d..6e8dccbccd515 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -12,7 +12,7 @@ use rustc_hir::{ Pat, PatExpr, PatExprKind, PatField, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, StructTailExpr, TraitBoundModifiers, Ty, TyKind, TyPat, TyPatKind, }; -use rustc_lexer::{TokenKind, tokenize}; +use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::LateContext; use rustc_middle::ty::TypeckResults; use rustc_span::{BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext, sym}; @@ -686,7 +686,7 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' // `{}` => `()` ([], None) if block.span.check_source_text(cx, |src| { - tokenize(src) + tokenize(src, FrontmatterAllowed::No) .map(|t| t.kind) .filter(|t| { !matches!( diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index c01f0ffaac9a0..98b4c183b1206 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -106,7 +106,7 @@ use rustc_hir::{ Param, Pat, PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Stmt, StmtKind, TraitFn, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp, def, }; -use rustc_lexer::{TokenKind, tokenize}; +use rustc_lexer::{FrontmatterAllowed, TokenKind, tokenize}; use rustc_lint::{LateContext, Level, Lint, LintContext}; use rustc_middle::hir::nested_filter; use rustc_middle::hir::place::PlaceBase; @@ -2764,7 +2764,7 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &Expr<'tcx>) -> ExprUseCtx /// Tokenizes the input while keeping the text associated with each token. pub fn tokenize_with_text(s: &str) -> impl Iterator { let mut pos = 0; - tokenize(s).map(move |t| { + tokenize(s, FrontmatterAllowed::No).map(move |t| { let end = pos + t.len; let range = pos as usize..end as usize; let inner = InnerSpan::new(range.start, range.end); @@ -2779,7 +2779,7 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { let Ok(snippet) = sm.span_to_snippet(span) else { return false; }; - return tokenize(&snippet).any(|token| { + return tokenize(&snippet, FrontmatterAllowed::No).any(|token| { matches!( token.kind, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 7f2bf99daff20..7d21336be1cd8 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use rustc_ast::{LitKind, StrStyle}; use rustc_errors::Applicability; use rustc_hir::{BlockCheckMode, Expr, ExprKind, UnsafeSource}; -use rustc_lexer::{LiteralKind, TokenKind, tokenize}; +use rustc_lexer::{FrontmatterAllowed, LiteralKind, TokenKind, tokenize}; use rustc_lint::{EarlyContext, LateContext}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -277,7 +277,7 @@ fn map_range( } fn ends_with_line_comment_or_broken(text: &str) -> bool { - let Some(last) = tokenize(text).last() else { + let Some(last) = tokenize(text, FrontmatterAllowed::No).last() else { return false; }; match last.kind { @@ -310,7 +310,8 @@ fn with_leading_whitespace_inner(lines: &[RelativeBytePos], src: &str, range: Ra && ends_with_line_comment_or_broken(&start[prev_start..]) && let next_line = lines.partition_point(|&pos| pos.to_usize() < range.end) && let next_start = lines.get(next_line).map_or(src.len(), |&x| x.to_usize()) - && tokenize(src.get(range.end..next_start)?).any(|t| !matches!(t.kind, TokenKind::Whitespace)) + && tokenize(src.get(range.end..next_start)?, FrontmatterAllowed::No) + .any(|t| !matches!(t.kind, TokenKind::Whitespace)) { Some(range.start) } else { diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs index e6c92dec68107..bff9acd78fa0f 100644 --- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs +++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs @@ -11,8 +11,8 @@ use std::ops; use rustc_literal_escaper::{ - EscapeError, Mode, unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, - unescape_str, + unescape_byte, unescape_byte_str, unescape_c_str, unescape_char, unescape_str, EscapeError, + Mode, }; use crate::{ @@ -44,7 +44,9 @@ impl<'a> LexedStr<'a> { // Re-create the tokenizer from scratch every token because `GuardedStrPrefix` is one token in the lexer // but we want to split it to two in edition <2024. - while let Some(token) = rustc_lexer::tokenize(&text[conv.offset..]).next() { + while let Some(token) = + rustc_lexer::tokenize(&text[conv.offset..], rustc_lexer::FrontmatterAllowed::No).next() + { let token_text = &text[conv.offset..][..token.len as usize]; conv.extend_token(&token.kind, token_text); @@ -58,7 +60,7 @@ impl<'a> LexedStr<'a> { return None; } - let token = rustc_lexer::tokenize(text).next()?; + let token = rustc_lexer::tokenize(text, rustc_lexer::FrontmatterAllowed::No).next()?; if token.len as usize != text.len() { return None; } diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs index dd576f23ae9fd..662f6257642f0 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl.rs @@ -121,7 +121,7 @@ pub(super) fn literal_from_str( use proc_macro::bridge::LitKind; use rustc_lexer::{LiteralKind, Token, TokenKind}; - let mut tokens = rustc_lexer::tokenize(s); + let mut tokens = rustc_lexer::tokenize(s, rustc_lexer::FrontmatterAllowed::No); let minus_or_lit = tokens.next().unwrap_or(Token { kind: TokenKind::Eof, len: 0 }); let lit = if minus_or_lit.kind == TokenKind::Minus { diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs index 14574a6456bda..44123385c8cc3 100644 --- a/src/tools/rust-analyzer/crates/tt/src/lib.rs +++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs @@ -579,7 +579,7 @@ where { use rustc_lexer::LiteralKind; - let token = rustc_lexer::tokenize(text).next_tuple(); + let token = rustc_lexer::tokenize(text, rustc_lexer::FrontmatterAllowed::No).next_tuple(); let Some((rustc_lexer::Token { kind: rustc_lexer::TokenKind::Literal { kind, suffix_start }, .. diff --git a/tests/codegen/intrinsics/transmute.rs b/tests/codegen/intrinsics/transmute.rs index e375724bc1bbd..c9a1cd58af338 100644 --- a/tests/codegen/intrinsics/transmute.rs +++ b/tests/codegen/intrinsics/transmute.rs @@ -29,28 +29,28 @@ pub struct Aggregate8(u8); // CHECK-LABEL: @check_bigger_size( #[no_mangle] pub unsafe fn check_bigger_size(x: u16) -> u32 { - // CHECK: call void @llvm.assume(i1 false) + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_size( #[no_mangle] pub unsafe fn check_smaller_size(x: u32) -> u16 { - // CHECK: call void @llvm.assume(i1 false) + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } // CHECK-LABEL: @check_smaller_array( #[no_mangle] pub unsafe fn check_smaller_array(x: [u32; 7]) -> [u32; 3] { - // CHECK: call void @llvm.assume(i1 false) + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } // CHECK-LABEL: @check_bigger_array( #[no_mangle] pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { - // CHECK: call void @llvm.assume(i1 false) + // CHECK: store i1 true, ptr poison, align 1 transmute_unchecked(x) } @@ -58,9 +58,9 @@ pub unsafe fn check_bigger_array(x: [u32; 3]) -> [u32; 7] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { { RET = CastTransmute(x); @@ -73,9 +73,9 @@ pub unsafe fn check_to_empty_array(x: [u32; 5]) -> [u32; 0] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { - // CHECK-NOT: call - // CHECK: call void @llvm.assume(i1 false) - // CHECK-NOT: call + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { { RET = CastTransmute(x); @@ -88,9 +88,9 @@ pub unsafe fn check_from_empty_array(x: [u32; 0]) -> [u32; 5] { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_to_uninhabited(x: u16) { - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { let temp: BigNever; { @@ -104,7 +104,9 @@ pub unsafe fn check_to_uninhabited(x: u16) { #[no_mangle] #[custom_mir(dialect = "runtime", phase = "optimized")] pub unsafe fn check_from_uninhabited(x: BigNever) -> u16 { - // CHECK: ret i16 poison + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret i16 poison mir! { { RET = CastTransmute(x); @@ -401,9 +403,9 @@ pub unsafe fn check_issue_109992(x: ()) -> [(); 1] { pub unsafe fn check_unit_to_never(x: ()) { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. - // CHECK-NOT: trap - // CHECK: call void @llvm.trap - // CHECK-NOT: trap + // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 + // CHECK-NEXT: ret void mir! { let temp: ZstNever; { @@ -420,6 +422,7 @@ pub unsafe fn check_unit_from_never(x: ZstNever) -> () { // This uses custom MIR to avoid MIR optimizations having removed ZST ops. // CHECK: start + // CHECK-NEXT: store i1 true, ptr poison, align 1 // CHECK-NEXT: ret void mir! { { diff --git a/tests/ui/allocator/weak-uninhabited-type.rs b/tests/ui/allocator/weak-uninhabited-type.rs new file mode 100644 index 0000000000000..74258eedc6ac3 --- /dev/null +++ b/tests/ui/allocator/weak-uninhabited-type.rs @@ -0,0 +1,13 @@ +//! Checks that `Weak` pointers can be created with an empty enum type parameter. +//! And generic `Weak` handles zero-variant enums without error. +//! +//! Regression test for + +//@ run-pass + +enum Void {} + +fn main() { + let _ = std::rc::Weak::::new(); + let _ = std::sync::Weak::::new(); +} diff --git a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr index a7647cf26aadf..71a1360cb5a22 100644 --- a/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/tests/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -42,7 +42,7 @@ LL + type X = ::Target; LL - type X = std::ops::Deref::Target; LL + type X = as Deref>::Target; | - and N other candidates + = and N other candidates error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:13:23 diff --git a/tests/ui/type-param-constraints.rs b/tests/ui/auto-traits/auto-traits-type-parameter.rs similarity index 59% rename from tests/ui/type-param-constraints.rs rename to tests/ui/auto-traits/auto-traits-type-parameter.rs index 83d81c0d833f1..0c448f5899672 100644 --- a/tests/ui/type-param-constraints.rs +++ b/tests/ui/auto-traits/auto-traits-type-parameter.rs @@ -1,24 +1,25 @@ +//! Checks how type parameters interact with auto-traits like `Send` and `Sync` with implicit +//! bounds + //@ run-pass #![allow(non_camel_case_types)] #![allow(dead_code)] -fn p_foo(_pinned: T) { } -fn s_foo(_shared: T) { } -fn u_foo(_unique: T) { } +fn p_foo(_pinned: T) {} +fn s_foo(_shared: T) {} +fn u_foo(_unique: T) {} struct r { - i: isize, + i: isize, } impl Drop for r { fn drop(&mut self) {} } -fn r(i:isize) -> r { - r { - i: i - } +fn r(i: isize) -> r { + r { i } } pub fn main() { diff --git a/tests/ui/binding/underscore-prefixed-function-argument.rs b/tests/ui/binding/underscore-prefixed-function-argument.rs new file mode 100644 index 0000000000000..e5b2ec1b5f005 --- /dev/null +++ b/tests/ui/binding/underscore-prefixed-function-argument.rs @@ -0,0 +1,15 @@ +//! Test that argument names starting with `_` are usable. + +//@ run-pass + +fn good(_a: &isize) {} + +fn called(_f: F) +where + F: FnOnce(&isize), +{ +} + +pub fn main() { + called(good); +} diff --git a/tests/ui/borrowck/ownership-struct-update-moved-error.rs b/tests/ui/borrowck/ownership-struct-update-moved-error.rs new file mode 100644 index 0000000000000..62fc1f42969f4 --- /dev/null +++ b/tests/ui/borrowck/ownership-struct-update-moved-error.rs @@ -0,0 +1,19 @@ +//! Checks borrow after move error when using `self` consuming method with struct update syntax. + +struct Mine { + test: String, + other_val: isize, +} + +impl Mine { + fn make_string_bar(mut self) -> Mine { + self.test = "Bar".to_string(); + self + } +} + +fn main() { + let start = Mine { test: "Foo".to_string(), other_val: 0 }; + let end = Mine { other_val: 1, ..start.make_string_bar() }; + println!("{}", start.test); //~ ERROR borrow of moved value: `start` +} diff --git a/tests/ui/walk-struct-literal-with.stderr b/tests/ui/borrowck/ownership-struct-update-moved-error.stderr similarity index 63% rename from tests/ui/walk-struct-literal-with.stderr rename to tests/ui/borrowck/ownership-struct-update-moved-error.stderr index 34b501f8ec881..83cfc7bb412cf 100644 --- a/tests/ui/walk-struct-literal-with.stderr +++ b/tests/ui/borrowck/ownership-struct-update-moved-error.stderr @@ -1,17 +1,17 @@ error[E0382]: borrow of moved value: `start` - --> $DIR/walk-struct-literal-with.rs:16:20 + --> $DIR/ownership-struct-update-moved-error.rs:18:20 | -LL | let start = Mine{test:"Foo".to_string(), other_val:0}; +LL | let start = Mine { test: "Foo".to_string(), other_val: 0 }; | ----- move occurs because `start` has type `Mine`, which does not implement the `Copy` trait -LL | let end = Mine{other_val:1, ..start.make_string_bar()}; - | ----------------- `start` moved due to this method call +LL | let end = Mine { other_val: 1, ..start.make_string_bar() }; + | ----------------- `start` moved due to this method call LL | println!("{}", start.test); | ^^^^^^^^^^ value borrowed here after move | note: `Mine::make_string_bar` takes ownership of the receiver `self`, which moves `start` - --> $DIR/walk-struct-literal-with.rs:7:28 + --> $DIR/ownership-struct-update-moved-error.rs:9:28 | -LL | fn make_string_bar(mut self) -> Mine{ +LL | fn make_string_bar(mut self) -> Mine { | ^^^^ = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/unused-move-capture.rs b/tests/ui/closures/no-capture-closure-call.rs similarity index 72% rename from tests/ui/unused-move-capture.rs rename to tests/ui/closures/no-capture-closure-call.rs index 5f42bcbe280e6..29e5ac635b421 100644 --- a/tests/ui/unused-move-capture.rs +++ b/tests/ui/closures/no-capture-closure-call.rs @@ -1,3 +1,5 @@ +//! Sanity check for no capture closures + //@ run-pass pub fn main() { diff --git a/tests/ui/unknown-llvm-arg.rs b/tests/ui/codegen/llvm-args-invalid-flag.rs similarity index 100% rename from tests/ui/unknown-llvm-arg.rs rename to tests/ui/codegen/llvm-args-invalid-flag.rs diff --git a/tests/ui/unknown-llvm-arg.stderr b/tests/ui/codegen/llvm-args-invalid-flag.stderr similarity index 100% rename from tests/ui/unknown-llvm-arg.stderr rename to tests/ui/codegen/llvm-args-invalid-flag.stderr diff --git a/tests/ui/const-generics/issues/issue-82956.stderr b/tests/ui/const-generics/issues/issue-82956.stderr index 5e380eea81cab..fd93e5122a5ef 100644 --- a/tests/ui/const-generics/issues/issue-82956.stderr +++ b/tests/ui/const-generics/issues/issue-82956.stderr @@ -14,7 +14,7 @@ LL + use std::collections::btree_map::IntoIter; | LL + use std::collections::btree_set::IntoIter; | - and 9 other candidates + = and 9 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-eval-array-len-in-impl.rs b/tests/ui/consts/const-eval-array-len-in-impl.rs new file mode 100644 index 0000000000000..0373274770de5 --- /dev/null +++ b/tests/ui/consts/const-eval-array-len-in-impl.rs @@ -0,0 +1,15 @@ +//! This checks that compiler correctly evaluate constant array lengths within trait `impl` headers. +//! +//! Regression test for . + +trait Foo { + fn foo(); +} + +impl Foo for [(); 1] { + fn foo() {} +} + +fn main() { + <[(); 0] as Foo>::foo() //~ ERROR E0277 +} diff --git a/tests/ui/unevaluated_fixed_size_array_len.stderr b/tests/ui/consts/const-eval-array-len-in-impl.stderr similarity index 86% rename from tests/ui/unevaluated_fixed_size_array_len.stderr rename to tests/ui/consts/const-eval-array-len-in-impl.stderr index 43cc377006e0e..faff7aa3ff7a7 100644 --- a/tests/ui/unevaluated_fixed_size_array_len.stderr +++ b/tests/ui/consts/const-eval-array-len-in-impl.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `[(); 0]: Foo` is not satisfied - --> $DIR/unevaluated_fixed_size_array_len.rs:12:6 + --> $DIR/const-eval-array-len-in-impl.rs:14:6 | LL | <[(); 0] as Foo>::foo() | ^^^^^^^ the trait `Foo` is not implemented for `[(); 0]` diff --git a/tests/ui/typestate-multi-decl.rs b/tests/ui/destructuring-assignment/let-binding-tuple-destructuring.rs similarity index 51% rename from tests/ui/typestate-multi-decl.rs rename to tests/ui/destructuring-assignment/let-binding-tuple-destructuring.rs index 3d0e79632bb33..f62fae8621934 100644 --- a/tests/ui/typestate-multi-decl.rs +++ b/tests/ui/destructuring-assignment/let-binding-tuple-destructuring.rs @@ -1,3 +1,5 @@ +//! Checks basic multiple variable declaration using tuple destructuring in a `let` binding. + //@ run-pass pub fn main() { diff --git a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr index 927f9e842e665..12965800a027f 100644 --- a/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr +++ b/tests/ui/did_you_mean/issue-56028-there-is-an-enum-variant.stderr @@ -18,7 +18,7 @@ LL + fn setup() -> Determine { Set } LL - fn setup() -> Set { Set } LL + fn setup() -> PutDown { Set } | - and 3 other candidates + = and 3 other candidates error[E0425]: cannot find value `Set` in this scope --> $DIR/issue-56028-there-is-an-enum-variant.rs:9:21 @@ -36,7 +36,7 @@ LL + use Determine::Set; | LL + use PutDown::Set; | - and 3 other candidates + = and 3 other candidates error: aborting due to 2 previous errors diff --git a/tests/ui/drop/box-drop-unused-value-statement-regression.rs b/tests/ui/drop/box-drop-unused-value-statement-regression.rs new file mode 100644 index 0000000000000..43865e0844457 --- /dev/null +++ b/tests/ui/drop/box-drop-unused-value-statement-regression.rs @@ -0,0 +1,12 @@ +//! Regression test for a crash caused by an "unsused move" +//! (specifically, a variable bound to a `Box` used as a statement) +//! leading to incorrect memory zero-filling after drop. +//! +//! Regression test for . + +//@ run-pass + +pub fn main() { + let y: Box<_> = Box::new(1); + drop(y); +} diff --git a/tests/ui/weird-exprs.rs b/tests/ui/expr/syntax-edge-cases-lint-clean.rs similarity index 100% rename from tests/ui/weird-exprs.rs rename to tests/ui/expr/syntax-edge-cases-lint-clean.rs diff --git a/tests/ui/wrong-hashset-issue-42918.rs b/tests/ui/hashmap/hashset-enum-variant.rs similarity index 61% rename from tests/ui/wrong-hashset-issue-42918.rs rename to tests/ui/hashmap/hashset-enum-variant.rs index 5795cc527cf27..39a59d3a39b63 100644 --- a/tests/ui/wrong-hashset-issue-42918.rs +++ b/tests/ui/hashmap/hashset-enum-variant.rs @@ -1,26 +1,27 @@ +//! Check for correct initialization of `HashSet` with enums. This is a regression test for a +//! codegen bug that caused the `HashSet` to appear as if it contained one of each enum variant. +//! +//! Regression test for + //@ run-pass -// -#![allow(dead_code)] //@ compile-flags: -O +#![allow(dead_code)] + use std::collections::HashSet; #[derive(PartialEq, Debug, Hash, Eq, Clone, PartialOrd, Ord)] enum MyEnum { E0, - E1, - E2, E3, E4, - E5, E6, E7, } - fn main() { use MyEnum::*; let s: HashSet<_> = [E4, E1].iter().cloned().collect(); diff --git a/tests/ui/impl-trait/call_method_without_import.no_import.stderr b/tests/ui/impl-trait/call_method_without_import.no_import.stderr index 72982b695bbb0..e59409ea27e64 100644 --- a/tests/ui/impl-trait/call_method_without_import.no_import.stderr +++ b/tests/ui/impl-trait/call_method_without_import.no_import.stderr @@ -30,7 +30,7 @@ LL + use std::fmt::Display; | LL + use std::fmt::LowerExp; | - and 5 other candidates + = and 5 other candidates error: aborting due to 2 previous errors diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr index 81336d51df4c6..371130facf9d3 100644 --- a/tests/ui/imports/issue-56125.stderr +++ b/tests/ui/imports/issue-56125.stderr @@ -18,7 +18,7 @@ LL + use ::issue_56125::issue_56125; LL - use empty::issue_56125; LL + use ::issue_56125::last_segment::issue_56125; | - and 1 other candidate + = and 1 other candidate error[E0659]: `issue_56125` is ambiguous --> $DIR/issue-56125.rs:6:9 diff --git a/tests/ui/write-fmt-errors.rs b/tests/ui/io-checks/write-macro-error.rs similarity index 82% rename from tests/ui/write-fmt-errors.rs rename to tests/ui/io-checks/write-macro-error.rs index b48fa3f11ccb1..857ea0024e16c 100644 --- a/tests/ui/write-fmt-errors.rs +++ b/tests/ui/io-checks/write-macro-error.rs @@ -1,3 +1,6 @@ +//! Tests that errors from both the writer (`Write::write`) and formatter (`Display::fmt`) +//! are correctly propagated: writer errors return `Err`, formatter errors cause panics. + //@ run-pass //@ needs-unwind @@ -24,7 +27,9 @@ impl Write for ErrorWriter { Err(Error::new(WRITER_ERROR, "not connected")) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } } fn main() { @@ -37,7 +42,8 @@ fn main() { let err = res.expect_err("formatter error did not lead to panic").downcast::<&str>().unwrap(); assert!( err.contains("formatting trait implementation returned an error"), - "unexpected panic: {}", err + "unexpected panic: {}", + err ); // Writer error when there's some string before the first `{}` @@ -50,6 +56,7 @@ fn main() { let err = res.expect_err("formatter error did not lead to panic").downcast::<&str>().unwrap(); assert!( err.contains("formatting trait implementation returned an error"), - "unexpected panic: {}", err + "unexpected panic: {}", + err ); } diff --git a/tests/ui/lang-items/lang-item-unknown-definition-error.rs b/tests/ui/lang-items/lang-item-unknown-definition-error.rs new file mode 100644 index 0000000000000..22812128c2d36 --- /dev/null +++ b/tests/ui/lang-items/lang-item-unknown-definition-error.rs @@ -0,0 +1,12 @@ +//! Checks that compiler prevernt attempting to define an unrecognized or unknown lang item + +#![allow(unused)] +#![feature(lang_items)] + +#[lang = "foo"] +fn bar() -> ! { + //~^^ ERROR definition of an unknown lang item: `foo` + loop {} +} + +fn main() {} diff --git a/tests/ui/unknown-language-item.stderr b/tests/ui/lang-items/lang-item-unknown-definition-error.stderr similarity index 82% rename from tests/ui/unknown-language-item.stderr rename to tests/ui/lang-items/lang-item-unknown-definition-error.stderr index 832f134241844..3b939757ac2b0 100644 --- a/tests/ui/unknown-language-item.stderr +++ b/tests/ui/lang-items/lang-item-unknown-definition-error.stderr @@ -1,5 +1,5 @@ error[E0522]: definition of an unknown lang item: `foo` - --> $DIR/unknown-language-item.rs:4:1 + --> $DIR/lang-item-unknown-definition-error.rs:6:1 | LL | #[lang = "foo"] | ^^^^^^^^^^^^^^^ definition of unknown lang item `foo` diff --git a/tests/ui/type-id-higher-rank-2.rs b/tests/ui/lifetimes/any-lifetime-escape-higher-rank.rs similarity index 76% rename from tests/ui/type-id-higher-rank-2.rs rename to tests/ui/lifetimes/any-lifetime-escape-higher-rank.rs index 7b0c7b5394084..f9f38ee532d9d 100644 --- a/tests/ui/type-id-higher-rank-2.rs +++ b/tests/ui/lifetimes/any-lifetime-escape-higher-rank.rs @@ -1,11 +1,15 @@ +//! Checks that `std::any::Any` cannot be used to circumvent lifetime rules +//! with higher-rank types. + //@ run-pass -// Test that we can't ignore lifetimes by going through Any. use std::any::Any; struct Foo<'a>(&'a str); -fn good(s: &String) -> Foo<'_> { Foo(s) } +fn good(s: &String) -> Foo<'_> { + Foo(s) +} fn bad1(s: String) -> Option<&'static str> { let a: Box = Box::new(good as fn(&String) -> Foo); @@ -17,7 +21,9 @@ trait AsStr<'a, 'b> { } impl<'a> AsStr<'a, 'a> for String { - fn get(&'a self) -> &'a str { self } + fn get(&'a self) -> &'a str { + self + } } fn bad2(s: String) -> Option<&'static str> { diff --git a/tests/ui/type_length_limit.rs b/tests/ui/limits/type-length-limit-enforcement.rs similarity index 66% rename from tests/ui/type_length_limit.rs rename to tests/ui/limits/type-length-limit-enforcement.rs index 87f5ffd76d7a6..3b34d6eb5c855 100644 --- a/tests/ui/type_length_limit.rs +++ b/tests/ui/limits/type-length-limit-enforcement.rs @@ -1,17 +1,19 @@ -//@ build-fail +//~ ERROR reached the type-length limit + +//! Checks the enforcement of the type-length limit +//! and its configurability via `#![type_length_limit]`. + //@ compile-flags: -Copt-level=0 -Zenforce-type-length-limit -//~^^ ERROR reached the type-length limit -// Test that the type length limit can be changed. -// The exact type depends on optimizations, so disable them. +//@ build-fail #![allow(dead_code)] -#![type_length_limit="8"] +#![type_length_limit = "8"] macro_rules! link { ($id:ident, $t:ty) => { pub type $id = ($t, $t, $t); - } + }; } link! { A1, B1 } @@ -26,7 +28,7 @@ link! { D, E } link! { E, F } link! { F, G, Option> } -pub struct G(std::marker::PhantomData::<(T, K)>); +pub struct G(std::marker::PhantomData<(T, K)>); fn main() { drop::>(None); diff --git a/tests/ui/type_length_limit.stderr b/tests/ui/limits/type-length-limit-enforcement.stderr similarity index 86% rename from tests/ui/type_length_limit.stderr rename to tests/ui/limits/type-length-limit-enforcement.stderr index 198d133c08c88..516230ae832dc 100644 --- a/tests/ui/type_length_limit.stderr +++ b/tests/ui/limits/type-length-limit-enforcement.stderr @@ -1,11 +1,11 @@ error: reached the type-length limit while instantiating `std::mem::drop::>` - --> $DIR/type_length_limit.rs:32:5 + --> $DIR/type-length-limit-enforcement.rs:34:5 | LL | drop::>(None); | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: consider adding a `#![type_length_limit="4010"]` attribute to your crate - = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit.long-type.txt' + = note: the full type name has been written to '$TEST_BUILD_DIR/type-length-limit-enforcement.long-type.txt' error: reached the type-length limit while instantiating `<{closure@rt::lang_start<()>::{closure#0}} as FnMut<()>>::call_mut` | diff --git a/tests/ui/lint/use_suggestion_json.stderr b/tests/ui/lint/use_suggestion_json.stderr index 0d4304e2e2e40..558c2260fcede 100644 --- a/tests/ui/lint/use_suggestion_json.stderr +++ b/tests/ui/lint/use_suggestion_json.stderr @@ -419,7 +419,7 @@ mod foo { \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m \u001b[0m\u001b[1m\u001b[38;5;12mLL\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[38;5;10m+ use std::collections::hash_map::Iter;\u001b[0m \u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m|\u001b[0m -\u001b[0m and 9 other candidates\u001b[0m +\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;12m= \u001b[0m\u001b[0mand 9 other candidates\u001b[0m " } diff --git a/tests/ui/macros/macro-fragment-ident-underscore-error.rs b/tests/ui/macros/macro-fragment-ident-underscore-error.rs new file mode 100644 index 0000000000000..882dd167adc7d --- /dev/null +++ b/tests/ui/macros/macro-fragment-ident-underscore-error.rs @@ -0,0 +1,12 @@ +//! Verifies that the reserved underscore `_` cannot be used as an `ident` fragment specifier +//! within a macro pattern, as it leads to a compilation error. + +macro_rules! identity { + ($i: ident) => { + $i + }; +} + +fn main() { + let identity!(_) = 10; //~ ERROR no rules expected reserved identifier `_` +} diff --git a/tests/ui/underscore-ident-matcher.stderr b/tests/ui/macros/macro-fragment-ident-underscore-error.stderr similarity index 72% rename from tests/ui/underscore-ident-matcher.stderr rename to tests/ui/macros/macro-fragment-ident-underscore-error.stderr index 0c3f980cf6c71..929e4624e4b2e 100644 --- a/tests/ui/underscore-ident-matcher.stderr +++ b/tests/ui/macros/macro-fragment-ident-underscore-error.stderr @@ -1,5 +1,5 @@ error: no rules expected reserved identifier `_` - --> $DIR/underscore-ident-matcher.rs:8:19 + --> $DIR/macro-fragment-ident-underscore-error.rs:11:19 | LL | macro_rules! identity { | --------------------- when calling this macro @@ -8,9 +8,9 @@ LL | let identity!(_) = 10; | ^ no rules expected this token in macro call | note: while trying to match meta-variable `$i:ident` - --> $DIR/underscore-ident-matcher.rs:2:6 + --> $DIR/macro-fragment-ident-underscore-error.rs:5:6 | -LL | ($i: ident) => ( +LL | ($i: ident) => { | ^^^^^^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/modules/module-qualified-paths-basic.rs b/tests/ui/modules/module-qualified-paths-basic.rs new file mode 100644 index 0000000000000..c02f6060caa71 --- /dev/null +++ b/tests/ui/modules/module-qualified-paths-basic.rs @@ -0,0 +1,20 @@ +//! Checks that functions from different modules are accessible via their fully-qualified paths. + +//@ run-pass + +mod foo { + pub fn x() -> isize { + return 1; + } +} + +mod bar { + pub fn y() -> isize { + return 1; + } +} + +pub fn main() { + foo::x(); + bar::y(); +} diff --git a/tests/ui/use-nested-groups.rs b/tests/ui/modules/module-use-nested-groups.rs similarity index 85% rename from tests/ui/use-nested-groups.rs rename to tests/ui/modules/module-use-nested-groups.rs index c5d66a8693533..84d1f9141a899 100644 --- a/tests/ui/use-nested-groups.rs +++ b/tests/ui/modules/module-use-nested-groups.rs @@ -1,3 +1,5 @@ +//! Checks complex `use` syntax and availability of types across nested modules. + //@ run-pass mod a { diff --git a/tests/ui/modules/primitive-type-module-deprecated-paths.rs b/tests/ui/modules/primitive-type-module-deprecated-paths.rs new file mode 100644 index 0000000000000..5c9d2a616b3f0 --- /dev/null +++ b/tests/ui/modules/primitive-type-module-deprecated-paths.rs @@ -0,0 +1,13 @@ +//! Make sure the module level constants are still there and accessible even after +//! the corresponding associated constants have been added, and later stabilized. + +//@ run-pass + +#![allow(deprecated, deprecated_in_future)] +use std::{f32, u16}; + +fn main() { + let _ = u16::MAX; + let _ = f32::EPSILON; + let _ = std::f64::MANTISSA_DIGITS; +} diff --git a/tests/ui/use-keyword-2.rs b/tests/ui/modules/use-keyword-reexport-type-alias.rs similarity index 52% rename from tests/ui/use-keyword-2.rs rename to tests/ui/modules/use-keyword-reexport-type-alias.rs index 4f3d1ee500d80..c62bd9687ae62 100644 --- a/tests/ui/use-keyword-2.rs +++ b/tests/ui/modules/use-keyword-reexport-type-alias.rs @@ -1,18 +1,20 @@ +//! Checks module re-exports, aliasing with `pub use`, +//! and calling private methods via `Self` in an impl block. + //@ run-pass #![allow(unused_variables)] pub struct A; mod test { - pub use super :: A; - - pub use self :: A as B; + pub use self::A as B; + pub use super::A; } impl A { fn f() {} fn g() { - Self :: f() + Self::f() } } diff --git a/tests/ui/namespace/struct-type-and-function-name-coexistence.rs b/tests/ui/namespace/struct-type-and-function-name-coexistence.rs new file mode 100644 index 0000000000000..8d5ab3781b5c3 --- /dev/null +++ b/tests/ui/namespace/struct-type-and-function-name-coexistence.rs @@ -0,0 +1,14 @@ +//@ run-pass + +struct A { + a: isize, +} + +fn a(a: A) -> isize { + return a.a; +} + +pub fn main() { + let x: A = A { a: 1 }; + assert_eq!(a(x), 1); +} diff --git a/tests/ui/unsigned-literal-negation.rs b/tests/ui/numbers-arithmetic/unary-negation-unsigned-integer-error.rs similarity index 69% rename from tests/ui/unsigned-literal-negation.rs rename to tests/ui/numbers-arithmetic/unary-negation-unsigned-integer-error.rs index 943c7f79742ab..4325c8b111bc5 100644 --- a/tests/ui/unsigned-literal-negation.rs +++ b/tests/ui/numbers-arithmetic/unary-negation-unsigned-integer-error.rs @@ -1,3 +1,5 @@ +//! This test ensures that the unary negation operator (`-`) cannot be applied to unsigned ints + fn main() { let x = -1 as usize; //~ ERROR: cannot apply unary operator `-` let x = (-1) as usize; //~ ERROR: cannot apply unary operator `-` diff --git a/tests/ui/unsigned-literal-negation.stderr b/tests/ui/numbers-arithmetic/unary-negation-unsigned-integer-error.stderr similarity index 86% rename from tests/ui/unsigned-literal-negation.stderr rename to tests/ui/numbers-arithmetic/unary-negation-unsigned-integer-error.stderr index 0bedbc1accd3b..4ce870ded9f76 100644 --- a/tests/ui/unsigned-literal-negation.stderr +++ b/tests/ui/numbers-arithmetic/unary-negation-unsigned-integer-error.stderr @@ -1,5 +1,5 @@ error[E0600]: cannot apply unary operator `-` to type `usize` - --> $DIR/unsigned-literal-negation.rs:2:13 + --> $DIR/unary-negation-unsigned-integer-error.rs:4:13 | LL | let x = -1 as usize; | ^^ cannot apply unary operator `-` @@ -12,7 +12,7 @@ LL + let x = usize::MAX; | error[E0600]: cannot apply unary operator `-` to type `usize` - --> $DIR/unsigned-literal-negation.rs:3:13 + --> $DIR/unary-negation-unsigned-integer-error.rs:5:13 | LL | let x = (-1) as usize; | ^^^^ cannot apply unary operator `-` @@ -25,7 +25,7 @@ LL + let x = usize::MAX; | error[E0600]: cannot apply unary operator `-` to type `u32` - --> $DIR/unsigned-literal-negation.rs:4:18 + --> $DIR/unary-negation-unsigned-integer-error.rs:6:18 | LL | let x: u32 = -1; | ^^ cannot apply unary operator `-` diff --git a/tests/ui/unwind-no-uwtable.rs b/tests/ui/panics/unwind-force-no-unwind-tables.rs similarity index 57% rename from tests/ui/unwind-no-uwtable.rs rename to tests/ui/panics/unwind-force-no-unwind-tables.rs index fb8082e31880a..2226e4dd03ebc 100644 --- a/tests/ui/unwind-no-uwtable.rs +++ b/tests/ui/panics/unwind-force-no-unwind-tables.rs @@ -1,3 +1,7 @@ +//! This test checks that Rust's unwinding mechanism correctly executes `Drop` +//! implementations during stack unwinding, even when unwind tables (`uwtable`) +//! are explicitly disabled via `-C force-unwind-tables=n`. + //@ run-pass //@ needs-unwind //@ ignore-windows target requires uwtable @@ -26,9 +30,12 @@ fn increase(count: &mut u8) { fn main() { let mut count = 0; - assert!(panic::catch_unwind(AssertUnwindSafe( - #[inline(never)] - || increase(&mut count) - )).is_err()); + assert!( + panic::catch_unwind(AssertUnwindSafe( + #[inline(never)] + || increase(&mut count) + )) + .is_err() + ); assert_eq!(count, 1); } diff --git a/tests/ui/parser/integer-literal-method-call-underscore.rs b/tests/ui/parser/integer-literal-method-call-underscore.rs new file mode 100644 index 0000000000000..9e4abf28cbaa6 --- /dev/null +++ b/tests/ui/parser/integer-literal-method-call-underscore.rs @@ -0,0 +1,15 @@ +//! Checks that methods with names starting with an underscore (`_`) can be +//! successfully called directly on integer literals, confirming the correct +//! parsing of such expressions where the underscore is part of the method identifier. + +//@ run-pass + +trait Tr: Sized { + fn _method_on_numbers(self) {} +} + +impl Tr for i32 {} + +fn main() { + 42._method_on_numbers(); +} diff --git a/tests/ui/privacy/suggest-box-new.stderr b/tests/ui/privacy/suggest-box-new.stderr index b651348de29ea..6c47b52c9de74 100644 --- a/tests/ui/privacy/suggest-box-new.stderr +++ b/tests/ui/privacy/suggest-box-new.stderr @@ -63,7 +63,7 @@ LL - x: (), LL - })), LL + wtf: Some(Box::new_in(_, _)), | - and 12 other candidates + = and 12 other candidates help: consider using the `Default` trait | LL - wtf: Some(Box(U { @@ -118,7 +118,7 @@ LL + let _ = Box::new_zeroed(); LL - let _ = Box {}; LL + let _ = Box::new_in(_, _); | - and 12 other candidates + = and 12 other candidates help: consider using the `Default` trait | LL - let _ = Box {}; diff --git a/tests/ui/wait-forked-but-failed-child.rs b/tests/ui/process/process-spawn-failure.rs similarity index 55% rename from tests/ui/wait-forked-but-failed-child.rs rename to tests/ui/process/process-spawn-failure.rs index 4a7f2bee9d954..0950b044c97ca 100644 --- a/tests/ui/wait-forked-but-failed-child.rs +++ b/tests/ui/process/process-spawn-failure.rs @@ -1,3 +1,9 @@ +//! Tests that repeatedly spawning a failing command does not create zombie processes. +//! Spawns a deliberately invalid command multiple times, verifies each spawn fails, +//! then uses `ps` (on Unix) to detect any leftover zombie (defunct) child processes. +//! Checks Rust's process spawning cleans up resources properly. +//! Skipped on platforms without `ps` utility. + //@ run-pass //@ needs-subprocess //@ ignore-vxworks no 'ps' @@ -36,35 +42,42 @@ fn find_zombies() { // the PPID column contains a "-" for the respective process. // Filter out any lines that have a "-" as the PPID as the PPID is // expected to be an integer. - let filtered_ps: Vec<_> = ps_output - .lines() - .filter(|line| line.split_whitespace().nth(1) != Some("-")) - .collect(); + let filtered_ps: Vec<_> = + ps_output.lines().filter(|line| line.split_whitespace().nth(1) != Some("-")).collect(); for (line_no, line) in filtered_ps.into_iter().enumerate() { - if 0 < line_no && 0 < line.len() && - my_pid == line.split(' ').filter(|w| 0 < w.len()).nth(1) - .expect("1st column should be PPID") - .parse().ok() - .expect("PPID string into integer") && - line.contains("defunct") { + if 0 < line_no + && 0 < line.len() + && my_pid + == line + .split(' ') + .filter(|w| 0 < w.len()) + .nth(1) + .expect("1st column should be PPID") + .parse() + .ok() + .expect("PPID string into integer") + && line.contains("defunct") + { panic!("Zombie child {}", line); } } } #[cfg(windows)] -fn find_zombies() { } +fn find_zombies() {} fn main() { let too_long = format!("/NoSuchCommand{:0300}", 0u8); - let _failures = (0..100).map(|_| { - let mut cmd = Command::new(&too_long); - let failed = cmd.spawn(); - assert!(failed.is_err(), "Make sure the command fails to spawn(): {:?}", cmd); - failed - }).collect::>(); + let _failures = (0..100) + .map(|_| { + let mut cmd = Command::new(&too_long); + let failed = cmd.spawn(); + assert!(failed.is_err(), "Make sure the command fails to spawn(): {:?}", cmd); + failed + }) + .collect::>(); find_zombies(); // then _failures goes out of scope diff --git a/tests/ui/process/windows-exit-code-still-active.rs b/tests/ui/process/windows-exit-code-still-active.rs new file mode 100644 index 0000000000000..e661a4f6adc53 --- /dev/null +++ b/tests/ui/process/windows-exit-code-still-active.rs @@ -0,0 +1,26 @@ +//! On Windows the GetExitCodeProcess API is used to get the exit code of a +//! process, but it's easy to mistake a process exiting with the code 259 as +//! "still running" because this is the value of the STILL_ACTIVE constant. Make +//! sure we handle this case in the standard library and correctly report the +//! status. +//! +//! Note that this is disabled on unix as processes exiting with 259 will have +//! their exit status truncated to 3 (only the lower 8 bits are used). + +//@ run-pass + +#[cfg(windows)] +fn main() { + use std::env; + use std::process::{self, Command}; + + if env::args().len() == 1 { + let status = Command::new(env::current_exe().unwrap()).arg("foo").status().unwrap(); + assert_eq!(status.code(), Some(259)); + } else { + process::exit(259); + } +} + +#[cfg(not(windows))] +fn main() {} diff --git a/tests/ui/ptr_ops/ptr-write-bool-representation.rs b/tests/ui/ptr_ops/ptr-write-bool-representation.rs new file mode 100644 index 0000000000000..3dfc3e51ab298 --- /dev/null +++ b/tests/ui/ptr_ops/ptr-write-bool-representation.rs @@ -0,0 +1,18 @@ +//! Validates the correct behavior of writing a `bool` value using `std::ptr::write`. +//! +//! This test addresses historical concerns regarding the internal representation of `bool` +//! (e.g., as `i1` in LLVM versus its byte-aligned memory layout) and checks that +//! `ptr::write` correctly handles this type without issues, confirming its memory +//! behavior is as expected. + +//@ run-pass + +use std::ptr; + +pub fn main() { + unsafe { + let mut x: bool = false; + // this line breaks it + ptr::write(&mut x, false); + } +} diff --git a/tests/ui/ptr_ops/raw-pointer-type-basic.rs b/tests/ui/ptr_ops/raw-pointer-type-basic.rs new file mode 100644 index 0000000000000..349e8e67909fd --- /dev/null +++ b/tests/ui/ptr_ops/raw-pointer-type-basic.rs @@ -0,0 +1,18 @@ +//! Checks the basic usage of raw pointers (`*const isize`) as function argument and return types. + +//@ run-pass + +#![allow(dead_code)] + +fn f(a: *const isize) -> *const isize { + return a; +} + +fn g(a: *const isize) -> *const isize { + let b = f(a); + return b; +} + +pub fn main() { + return; +} diff --git a/tests/ui/reachable/diverging-expressions-unreachable-code.rs b/tests/ui/reachable/diverging-expressions-unreachable-code.rs new file mode 100644 index 0000000000000..bb56987775ff2 --- /dev/null +++ b/tests/ui/reachable/diverging-expressions-unreachable-code.rs @@ -0,0 +1,19 @@ +//@ run-pass + +#![allow(unused_must_use)] +#![allow(unreachable_code)] + +fn _id(x: bool) -> bool { + x +} + +fn _call_id() { + let _c = panic!(); + _id(_c); +} + +fn _call_id_3() { + _id(return) && _id(return); +} + +pub fn main() {} diff --git a/tests/ui/unreachable-code.rs b/tests/ui/reachable/unreachable-code-diverging-expressions.rs similarity index 76% rename from tests/ui/unreachable-code.rs rename to tests/ui/reachable/unreachable-code-diverging-expressions.rs index 0c46a38d73f35..00676418002c9 100644 --- a/tests/ui/unreachable-code.rs +++ b/tests/ui/reachable/unreachable-code-diverging-expressions.rs @@ -26,9 +26,13 @@ fn call_id_3() { fn ret_guard() { match 2 { - x if (return) => { x; } - x if let true = return => { x; } - _ => {} + x if (return) => { + x; + } + x if let true = return => { + x; + } + _ => {} } } diff --git a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr index ee1a336ea98f6..0eb1d46637bd5 100644 --- a/tests/ui/rust-2018/issue-52202-use-suggestions.stderr +++ b/tests/ui/rust-2018/issue-52202-use-suggestions.stderr @@ -14,7 +14,7 @@ LL + use std::collections::hash_map::Drain; | LL + use std::collections::hash_set::Drain; | - and 3 other candidates + = and 3 other candidates error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/multi-suggestion.ascii.stderr b/tests/ui/suggestions/multi-suggestion.ascii.stderr new file mode 100644 index 0000000000000..f2a146fbd5257 --- /dev/null +++ b/tests/ui/suggestions/multi-suggestion.ascii.stderr @@ -0,0 +1,130 @@ +error[E0423]: expected function, tuple struct or tuple variant, found struct `std::collections::HashMap` + --> $DIR/multi-suggestion.rs:17:13 + | +LL | let _ = std::collections::HashMap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + --> $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + | + = note: `std::collections::HashMap` defined here + | +help: you might have meant to use an associated function to build this type + | +LL | let _ = std::collections::HashMap::new(); + | +++++ +LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::with_capacity(_); + | +LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::with_hasher(_); + | +LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); + | +help: consider using the `Default` trait + | +LL | let _ = ::default(); + | + ++++++++++++++++++++++++++++++++++ + +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/multi-suggestion.rs:11:19 + | +LL | wtf: Some(Box(U { + | ^^^ + | +note: constructor is not visible here due to private fields + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: private field + | + = note: private field +help: you might have meant to use an associated function to build this type + | +LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), +LL + wtf: Some(Box::new(_)), + | +LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), +LL + wtf: Some(Box::new_uninit()), + | +LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), +LL + wtf: Some(Box::new_zeroed()), + | +LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), +LL + wtf: Some(Box::new_in(_, _)), + | + = and 12 other candidates +help: consider using the `Default` trait + | +LL - wtf: Some(Box(U { +LL + wtf: Some(::default()), + | + +error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields + --> $DIR/multi-suggestion.rs:19:13 + | +LL | let _ = std::collections::HashMap {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: private field `base` that was not provided +help: you might have meant to use an associated function to build this type + | +LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::new(); + | +LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::with_capacity(_); + | +LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::with_hasher(_); + | +LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); + | +help: consider using the `Default` trait + | +LL - let _ = std::collections::HashMap {}; +LL + let _ = ::default(); + | + +error: cannot construct `Box<_, _>` with struct literal syntax due to private fields + --> $DIR/multi-suggestion.rs:21:13 + | +LL | let _ = Box {}; + | ^^^ + | + = note: private fields `0` and `1` that were not provided +help: you might have meant to use an associated function to build this type + | +LL - let _ = Box {}; +LL + let _ = Box::new(_); + | +LL - let _ = Box {}; +LL + let _ = Box::new_uninit(); + | +LL - let _ = Box {}; +LL + let _ = Box::new_zeroed(); + | +LL - let _ = Box {}; +LL + let _ = Box::new_in(_, _); + | + = and 12 other candidates +help: consider using the `Default` trait + | +LL - let _ = Box {}; +LL + let _ = ::default(); + | + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/suggestions/multi-suggestion.rs b/tests/ui/suggestions/multi-suggestion.rs new file mode 100644 index 0000000000000..99d2407aa212a --- /dev/null +++ b/tests/ui/suggestions/multi-suggestion.rs @@ -0,0 +1,22 @@ +//@ revisions: ascii unicode +//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode + +#![allow(dead_code)] +struct U { + wtf: Option>>, + x: T, +} +fn main() { + U { + wtf: Some(Box(U { //[ascii]~ ERROR cannot initialize a tuple struct which contains private fields + wtf: None, + x: (), + })), + x: () + }; + let _ = std::collections::HashMap(); + //[ascii]~^ ERROR expected function, tuple struct or tuple variant, found struct `std::collections::HashMap` + let _ = std::collections::HashMap {}; + //[ascii]~^ ERROR cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields + let _ = Box {}; //[ascii]~ ERROR cannot construct `Box<_, _>` with struct literal syntax due to private fields +} diff --git a/tests/ui/suggestions/multi-suggestion.unicode.stderr b/tests/ui/suggestions/multi-suggestion.unicode.stderr new file mode 100644 index 0000000000000..69df481579bc7 --- /dev/null +++ b/tests/ui/suggestions/multi-suggestion.unicode.stderr @@ -0,0 +1,130 @@ +error[E0423]: expected function, tuple struct or tuple variant, found struct `std::collections::HashMap` + ╭▸ $DIR/multi-suggestion.rs:17:13 + │ +LL │ let _ = std::collections::HashMap(); + │ ━━━━━━━━━━━━━━━━━━━━━━━━━━━ + ╭▸ $SRC_DIR/std/src/collections/hash/map.rs:LL:COL + │ + ╰ note: `std::collections::HashMap` defined here + ╰╴ +help: you might have meant to use an associated function to build this type + ╭╴ +LL │ let _ = std::collections::HashMap::new(); + ├╴ +++++ +LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::with_capacity(_); + ├╴ +LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::with_hasher(_); + ├╴ +LL - let _ = std::collections::HashMap(); +LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); + ╰╴ +help: consider using the `Default` trait + ╭╴ +LL │ let _ = ::default(); + ╰╴ + ++++++++++++++++++++++++++++++++++ + +error[E0423]: cannot initialize a tuple struct which contains private fields + ╭▸ $DIR/multi-suggestion.rs:11:19 + │ +LL │ wtf: Some(Box(U { + │ ━━━ + ╰╴ +note: constructor is not visible here due to private fields + ╭▸ $SRC_DIR/alloc/src/boxed.rs:LL:COL + │ + ╰ note: private field + │ + ╰ note: private field +help: you might have meant to use an associated function to build this type + ╭╴ +LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), +LL + wtf: Some(Box::new(_)), + ├╴ +LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), +LL + wtf: Some(Box::new_uninit()), + ├╴ +LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), +LL + wtf: Some(Box::new_zeroed()), + ├╴ +LL - wtf: Some(Box(U { +LL - wtf: None, +LL - x: (), +LL - })), +LL + wtf: Some(Box::new_in(_, _)), + │ + ╰ and 12 other candidates +help: consider using the `Default` trait + ╭╴ +LL - wtf: Some(Box(U { +LL + wtf: Some(::default()), + ╰╴ + +error: cannot construct `HashMap<_, _, _>` with struct literal syntax due to private fields + ╭▸ $DIR/multi-suggestion.rs:19:13 + │ +LL │ let _ = std::collections::HashMap {}; + │ ━━━━━━━━━━━━━━━━━━━━━━━━━ + │ + ╰ note: private field `base` that was not provided +help: you might have meant to use an associated function to build this type + ╭╴ +LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::new(); + ├╴ +LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::with_capacity(_); + ├╴ +LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::with_hasher(_); + ├╴ +LL - let _ = std::collections::HashMap {}; +LL + let _ = std::collections::HashMap::with_capacity_and_hasher(_, _); + ╰╴ +help: consider using the `Default` trait + ╭╴ +LL - let _ = std::collections::HashMap {}; +LL + let _ = ::default(); + ╰╴ + +error: cannot construct `Box<_, _>` with struct literal syntax due to private fields + ╭▸ $DIR/multi-suggestion.rs:21:13 + │ +LL │ let _ = Box {}; + │ ━━━ + │ + ╰ note: private fields `0` and `1` that were not provided +help: you might have meant to use an associated function to build this type + ╭╴ +LL - let _ = Box {}; +LL + let _ = Box::new(_); + ├╴ +LL - let _ = Box {}; +LL + let _ = Box::new_uninit(); + ├╴ +LL - let _ = Box {}; +LL + let _ = Box::new_zeroed(); + ├╴ +LL - let _ = Box {}; +LL + let _ = Box::new_in(_, _); + │ + ╰ and 12 other candidates +help: consider using the `Default` trait + ╭╴ +LL - let _ = Box {}; +LL + let _ = ::default(); + ╰╴ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/ui/suggestions/too-many-field-suggestions.stderr b/tests/ui/suggestions/too-many-field-suggestions.stderr index ac5c8cb60ccdc..0cb0c8bec07f1 100644 --- a/tests/ui/suggestions/too-many-field-suggestions.stderr +++ b/tests/ui/suggestions/too-many-field-suggestions.stderr @@ -17,7 +17,7 @@ LL | t.a2.bar(); | +++ LL | t.a3.bar(); | +++ - and 6 other candidates + = and 6 other candidates error[E0609]: no field `field` on type `Thing` --> $DIR/too-many-field-suggestions.rs:26:7 @@ -35,7 +35,7 @@ LL | t.a2.field; | +++ LL | t.a3.field; | +++ - and 6 other candidates + = and 6 other candidates error: aborting due to 2 previous errors diff --git a/tests/ui/virtual-call-attrs-issue-137646.rs b/tests/ui/traits/virtual-call-parameter-handling.rs similarity index 77% rename from tests/ui/virtual-call-attrs-issue-137646.rs rename to tests/ui/traits/virtual-call-parameter-handling.rs index e80bd5768a429..71ed459d15aca 100644 --- a/tests/ui/virtual-call-attrs-issue-137646.rs +++ b/tests/ui/traits/virtual-call-parameter-handling.rs @@ -1,5 +1,7 @@ -//! Regression test for https://github.com/rust-lang/rust/issues/137646. -//! The parameter value at all calls to `check` should be `(1, 1, 1)`. +//! This test checks the correct parameter handling during virtual method calls +//! through a `dyn Trait` object. +//! +//! Regression test for: //@ run-pass diff --git a/tests/ui/try-operator-hygiene.rs b/tests/ui/try-operator-hygiene.rs deleted file mode 100644 index 20538e094c6d6..0000000000000 --- a/tests/ui/try-operator-hygiene.rs +++ /dev/null @@ -1,26 +0,0 @@ -//@ run-pass - -#![allow(non_upper_case_globals)] -#![allow(dead_code)] -// `expr?` expands to: -// -// match expr { -// Ok(val) => val, -// Err(err) => return Err(From::from(err)), -// } -// -// This test verifies that the expansion is hygienic, i.e., it's not affected by other `val` and -// `err` bindings that may be in scope. - -use std::num::ParseIntError; - -fn main() { - assert_eq!(parse(), Ok(1)); -} - -fn parse() -> Result { - const val: char = 'a'; - const err: char = 'b'; - - Ok("1".parse::()?) -} diff --git a/tests/ui/try-trait/try-operator-expansion-hygiene.rs b/tests/ui/try-trait/try-operator-expansion-hygiene.rs new file mode 100644 index 0000000000000..b6f4e533d8d4e --- /dev/null +++ b/tests/ui/try-trait/try-operator-expansion-hygiene.rs @@ -0,0 +1,24 @@ +//! This test verifies that the `?` operator expansion is hygienic, +//! i.e., it's not affected by other `val` and `err` bindings that may be in scope. +//! +//! Note: Prior to the Try trait stabilization, `expr?` expanded to a match +//! with `val` and `err` bindings. The current implementation uses Try::branch() +//! but this test remains relevant for hygiene verification. + +//@ run-pass + +#![allow(non_upper_case_globals)] +#![allow(dead_code)] + +use std::num::ParseIntError; + +fn main() { + assert_eq!(parse(), Ok(1)); +} + +fn parse() -> Result { + const val: char = 'a'; + const err: char = 'b'; + + Ok("1".parse::()?) +} diff --git a/tests/ui/try-operator.rs b/tests/ui/try-trait/try-operator-various-contexts.rs similarity index 86% rename from tests/ui/try-operator.rs rename to tests/ui/try-trait/try-operator-various-contexts.rs index b99782045575f..41c3679c96f6a 100644 --- a/tests/ui/try-operator.rs +++ b/tests/ui/try-trait/try-operator-various-contexts.rs @@ -1,9 +1,11 @@ +//! Checks the functionality of the `?` operator in various syntactic contexts. + //@ run-pass #![allow(dead_code)] use std::fs::File; -use std::io::{Read, self}; +use std::io::{self, Read}; use std::num::ParseIntError; use std::str::FromStr; @@ -35,7 +37,9 @@ fn on_path() -> Result { fn on_macro() -> Result { macro_rules! id { - ($e:expr) => { $e } + ($e:expr) => { + $e + }; } Ok(id!("7".parse::())?) @@ -50,11 +54,14 @@ fn on_parens() -> Result { fn on_block() -> Result { let x = "9".parse::(); - Ok({x}?) + Ok({ x }?) } fn on_field() -> Result { - struct Pair { a: A, b: B } + struct Pair { + a: A, + b: B, + } let x = Pair { a: "10".parse::(), b: 0 }; @@ -89,7 +96,9 @@ fn on_index() -> Result { } fn on_args() -> Result { - fn sub(x: i32, y: i32) -> i32 { x - y } + fn sub(x: i32, y: i32) -> i32 { + x - y + } let x = "20".parse(); let y = "21".parse(); @@ -98,19 +107,11 @@ fn on_args() -> Result { } fn on_if() -> Result { - Ok(if true { - "22".parse::() - } else { - "23".parse::() - }?) + Ok(if true { "22".parse::() } else { "23".parse::() }?) } fn on_if_let() -> Result { - Ok(if let Ok(..) = "24".parse::() { - "25".parse::() - } else { - "26".parse::() - }?) + Ok(if let Ok(..) = "24".parse::() { "25".parse::() } else { "26".parse::() }?) } fn on_match() -> Result { @@ -121,7 +122,9 @@ fn on_match() -> Result { } fn tight_binding() -> Result { - fn ok(x: T) -> Result { Ok(x) } + fn ok(x: T) -> Result { + Ok(x) + } let x = ok(true); Ok(!x?) diff --git a/tests/ui/tydesc-name.rs b/tests/ui/tydesc-name.rs deleted file mode 100644 index 068a42606c2f3..0000000000000 --- a/tests/ui/tydesc-name.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] - -use std::any::type_name; - -struct Foo { - x: T -} - -pub fn main() { - assert_eq!(type_name::(), "isize"); - assert_eq!(type_name::>(), "tydesc_name::Foo"); -} diff --git a/tests/ui/type-inference/type-inference-none-in-generic-ref.rs b/tests/ui/type-inference/type-inference-none-in-generic-ref.rs new file mode 100644 index 0000000000000..9c1b7c19e3da3 --- /dev/null +++ b/tests/ui/type-inference/type-inference-none-in-generic-ref.rs @@ -0,0 +1,9 @@ +//! Checks that unconstrained `None` is rejected through references and generics + +struct S<'a, T: 'a> { + o: &'a Option, +} + +fn main() { + S { o: &None }; //~ ERROR type annotations needed [E0282] +} diff --git a/tests/ui/unconstrained-ref.stderr b/tests/ui/type-inference/type-inference-none-in-generic-ref.stderr similarity index 87% rename from tests/ui/unconstrained-ref.stderr rename to tests/ui/type-inference/type-inference-none-in-generic-ref.stderr index 72fd0202f4e53..d671c189b3730 100644 --- a/tests/ui/unconstrained-ref.stderr +++ b/tests/ui/type-inference/type-inference-none-in-generic-ref.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/unconstrained-ref.rs:6:5 + --> $DIR/type-inference-none-in-generic-ref.rs:8:5 | LL | S { o: &None }; | ^^^^^^^^^^^^^^ cannot infer type of the type parameter `T` declared on the struct `S` diff --git a/tests/ui/type-inference/type-inference-unconstrained-none.rs b/tests/ui/type-inference/type-inference-unconstrained-none.rs new file mode 100644 index 0000000000000..38a506763c761 --- /dev/null +++ b/tests/ui/type-inference/type-inference-unconstrained-none.rs @@ -0,0 +1,5 @@ +//! Regression test for . + +fn main() { + None; //~ ERROR type annotations needed [E0282] +} diff --git a/tests/ui/unconstrained-none.stderr b/tests/ui/type-inference/type-inference-unconstrained-none.stderr similarity index 87% rename from tests/ui/unconstrained-none.stderr rename to tests/ui/type-inference/type-inference-unconstrained-none.stderr index 4af6f412e5b22..80572b845e84f 100644 --- a/tests/ui/unconstrained-none.stderr +++ b/tests/ui/type-inference/type-inference-unconstrained-none.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/unconstrained-none.rs:4:5 + --> $DIR/type-inference-unconstrained-none.rs:4:5 | LL | None; | ^^^^ cannot infer type of the type parameter `T` declared on the enum `Option` diff --git a/tests/ui/type-namespace.rs b/tests/ui/type-namespace.rs deleted file mode 100644 index 31dc684a214a7..0000000000000 --- a/tests/ui/type-namespace.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass - -struct A { a: isize } - -fn a(a: A) -> isize { return a.a; } - -pub fn main() { let x: A = A {a: 1}; assert_eq!(a(x), 1); } diff --git a/tests/ui/type-ptr.rs b/tests/ui/type-ptr.rs deleted file mode 100644 index 5c8ed344ab33a..0000000000000 --- a/tests/ui/type-ptr.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@ run-pass - -#![allow(dead_code)] - -fn f(a: *const isize) -> *const isize { return a; } - -fn g(a: *const isize) -> *const isize { let b = f(a); return b; } - -pub fn main() { return; } diff --git a/tests/ui/type-use-i1-versus-i8.rs b/tests/ui/type-use-i1-versus-i8.rs deleted file mode 100644 index 4eb25329223cf..0000000000000 --- a/tests/ui/type-use-i1-versus-i8.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass - -use std::ptr; - -pub fn main() { - unsafe { - let mut x: bool = false; - // this line breaks it - ptr::write(&mut x, false); - } -} diff --git a/tests/ui/auxiliary/typeid-intrinsic-aux1.rs b/tests/ui/type/auxiliary/typeid-consistency-aux1.rs similarity index 100% rename from tests/ui/auxiliary/typeid-intrinsic-aux1.rs rename to tests/ui/type/auxiliary/typeid-consistency-aux1.rs diff --git a/tests/ui/auxiliary/typeid-intrinsic-aux2.rs b/tests/ui/type/auxiliary/typeid-consistency-aux2.rs similarity index 100% rename from tests/ui/auxiliary/typeid-intrinsic-aux2.rs rename to tests/ui/type/auxiliary/typeid-consistency-aux2.rs diff --git a/tests/ui/type/type-name-basic.rs b/tests/ui/type/type-name-basic.rs new file mode 100644 index 0000000000000..9381cb8257811 --- /dev/null +++ b/tests/ui/type/type-name-basic.rs @@ -0,0 +1,17 @@ +//! Checks the basic functionality of `std::any::type_name` for primitive types +//! and simple generic structs. + +//@ run-pass + +#![allow(dead_code)] + +use std::any::type_name; + +struct Foo { + x: T, +} + +pub fn main() { + assert_eq!(type_name::(), "isize"); + assert_eq!(type_name::>(), "type_name_basic::Foo"); +} diff --git a/tests/ui/typeid-intrinsic.rs b/tests/ui/type/typeid-consistency.rs similarity index 85% rename from tests/ui/typeid-intrinsic.rs rename to tests/ui/type/typeid-consistency.rs index 7c4fb3f95a94e..67ee1b6d839ab 100644 --- a/tests/ui/typeid-intrinsic.rs +++ b/tests/ui/type/typeid-consistency.rs @@ -1,16 +1,18 @@ +//! Checks the correctness and consistency of `std::any::TypeId::of`. + //@ run-pass #![allow(deprecated)] -//@ aux-build:typeid-intrinsic-aux1.rs -//@ aux-build:typeid-intrinsic-aux2.rs - #![feature(core_intrinsics)] -extern crate typeid_intrinsic_aux1 as other1; -extern crate typeid_intrinsic_aux2 as other2; +//@ aux-build:typeid-consistency-aux1.rs +//@ aux-build:typeid-consistency-aux2.rs + +extern crate typeid_consistency_aux1 as other1; +extern crate typeid_consistency_aux2 as other2; -use std::hash::{SipHasher, Hasher, Hash}; use std::any::TypeId; +use std::hash::{Hash, Hasher, SipHasher}; struct A; struct Test; @@ -34,7 +36,7 @@ pub fn main() { assert_eq!(TypeId::of::(), other2::id_F()); assert_eq!(TypeId::of::(), other2::id_G()); assert_eq!(TypeId::of::(), other2::id_H()); - assert_eq!(TypeId::of::(), other2::id_I()); + assert_eq!(TypeId::of::(), other2::id_I()); assert_eq!(other1::id_F(), other2::id_F()); assert_eq!(other1::id_G(), other2::id_G()); @@ -49,10 +51,8 @@ pub fn main() { assert_eq!(other2::foo::(), other1::foo::()); // sanity test of TypeId - let (a, b, c) = (TypeId::of::(), TypeId::of::<&'static str>(), - TypeId::of::()); - let (d, e, f) = (TypeId::of::(), TypeId::of::<&'static str>(), - TypeId::of::()); + let (a, b, c) = (TypeId::of::(), TypeId::of::<&'static str>(), TypeId::of::()); + let (d, e, f) = (TypeId::of::(), TypeId::of::<&'static str>(), TypeId::of::()); assert!(a != b); assert!(a != c); @@ -82,10 +82,7 @@ pub fn main() { assert_ne!(TypeId::of::(), TypeId::of::()); // Check fn pointer against collisions - assert_ne!( - TypeId::of:: A) -> A>(), - TypeId::of:: A, A) -> A>() - ); + assert_ne!(TypeId::of:: A) -> A>(), TypeId::of:: A, A) -> A>()); assert_ne!( TypeId::of:: fn(&'a i32) -> &'a i32>(), TypeId::of:: fn(&'a i32) -> &'static i32>() diff --git a/tests/ui/type/unit-type-basic-usages.rs b/tests/ui/type/unit-type-basic-usages.rs new file mode 100644 index 0000000000000..c3ee8067f5918 --- /dev/null +++ b/tests/ui/type/unit-type-basic-usages.rs @@ -0,0 +1,14 @@ +//! Checks the basic usage of unit type + +//@ run-pass + +fn f(u: ()) { + u +} + +pub fn main() { + let u1: () = (); + let mut _u2: () = f(u1); + _u2 = (); + () +} diff --git a/tests/ui/usize-generic-argument-parent.rs b/tests/ui/type/usize-no-generic-arguments.rs similarity index 65% rename from tests/ui/usize-generic-argument-parent.rs rename to tests/ui/type/usize-no-generic-arguments.rs index 4ab80d944a56f..d4d1eea757cab 100644 --- a/tests/ui/usize-generic-argument-parent.rs +++ b/tests/ui/type/usize-no-generic-arguments.rs @@ -1,3 +1,5 @@ +//! Sanity test that primitives cannot have const generics. + fn foo() { let x: usize; //~ ERROR const arguments are not allowed on builtin type `usize` } diff --git a/tests/ui/usize-generic-argument-parent.stderr b/tests/ui/type/usize-no-generic-arguments.stderr similarity index 90% rename from tests/ui/usize-generic-argument-parent.stderr rename to tests/ui/type/usize-no-generic-arguments.stderr index 9c081a287ed75..f1f3456461fc6 100644 --- a/tests/ui/usize-generic-argument-parent.stderr +++ b/tests/ui/type/usize-no-generic-arguments.stderr @@ -1,5 +1,5 @@ error[E0109]: const arguments are not allowed on builtin type `usize` - --> $DIR/usize-generic-argument-parent.rs:2:18 + --> $DIR/usize-no-generic-arguments.rs:4:18 | LL | let x: usize; | ----- ^^^ const argument not allowed diff --git a/tests/ui/unconstrained-none.rs b/tests/ui/unconstrained-none.rs deleted file mode 100644 index e180b3163d412..0000000000000 --- a/tests/ui/unconstrained-none.rs +++ /dev/null @@ -1,5 +0,0 @@ -// Issue #5062 - -fn main() { - None; //~ ERROR type annotations needed [E0282] -} diff --git a/tests/ui/unconstrained-ref.rs b/tests/ui/unconstrained-ref.rs deleted file mode 100644 index 473ca954b232d..0000000000000 --- a/tests/ui/unconstrained-ref.rs +++ /dev/null @@ -1,7 +0,0 @@ -struct S<'a, T:'a> { - o: &'a Option -} - -fn main() { - S { o: &None }; //~ ERROR type annotations needed [E0282] -} diff --git a/tests/ui/underscore-ident-matcher.rs b/tests/ui/underscore-ident-matcher.rs deleted file mode 100644 index 77ec70d43d54e..0000000000000 --- a/tests/ui/underscore-ident-matcher.rs +++ /dev/null @@ -1,9 +0,0 @@ -macro_rules! identity { - ($i: ident) => ( - $i - ) -} - -fn main() { - let identity!(_) = 10; //~ ERROR no rules expected reserved identifier `_` -} diff --git a/tests/ui/underscore-lifetimes.rs b/tests/ui/underscore-lifetime/basic-underscore-lifetime-elision.rs similarity index 77% rename from tests/ui/underscore-lifetimes.rs rename to tests/ui/underscore-lifetime/basic-underscore-lifetime-elision.rs index a372851f9cfff..a2e3c8e26d4be 100644 --- a/tests/ui/underscore-lifetimes.rs +++ b/tests/ui/underscore-lifetime/basic-underscore-lifetime-elision.rs @@ -1,6 +1,9 @@ +//! Checks the correct usage and behavior of the anonymous lifetime `'_` (underscore lifetime) + //@ run-pass #![allow(dead_code, mismatched_lifetime_syntaxes)] + struct Foo<'a>(&'a u8); fn foo(x: &u8) -> Foo<'_> { @@ -31,8 +34,5 @@ fn main() { let _ = foo2(x); let _ = foo3(x); foo4(Foo(x)); - let _ = foo5(Foo2 { - a: x, - b: &6, - }); + let _ = foo5(Foo2 { a: x, b: &6 }); } diff --git a/tests/ui/underscore-method-after-integer.rs b/tests/ui/underscore-method-after-integer.rs deleted file mode 100644 index d9eb21894e8ca..0000000000000 --- a/tests/ui/underscore-method-after-integer.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass - -trait Tr : Sized { - fn _method_on_numbers(self) {} -} - -impl Tr for i32 {} - -fn main() { - 42._method_on_numbers(); -} diff --git a/tests/ui/unevaluated_fixed_size_array_len.rs b/tests/ui/unevaluated_fixed_size_array_len.rs deleted file mode 100644 index 6c545913dd9dc..0000000000000 --- a/tests/ui/unevaluated_fixed_size_array_len.rs +++ /dev/null @@ -1,13 +0,0 @@ -// https://github.com/rust-lang/rust/issues/49208 - -trait Foo { - fn foo(); -} - -impl Foo for [(); 1] { - fn foo() {} -} - -fn main() { - <[(); 0] as Foo>::foo() //~ ERROR E0277 -} diff --git a/tests/ui/unit.rs b/tests/ui/unit.rs deleted file mode 100644 index 04404fc3f5e66..0000000000000 --- a/tests/ui/unit.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ run-pass - -#![allow(unused_assignments)] -#![allow(unknown_lints)] - -#![allow(unused_variables)] -#![allow(dead_assignment)] - -fn f(u: ()) { return u; } - -pub fn main() { - let u1: () = (); - let mut u2: () = f(u1); - u2 = (); - return (); -} diff --git a/tests/ui/unknown-language-item.rs b/tests/ui/unknown-language-item.rs deleted file mode 100644 index ce206d20358a1..0000000000000 --- a/tests/ui/unknown-language-item.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![allow(unused)] -#![feature(lang_items)] - -#[lang = "foo"] -fn bar() -> ! { -//~^^ ERROR definition of an unknown lang item: `foo` - loop {} -} - -fn main() {} diff --git a/tests/ui/unnamed_argument_mode.rs b/tests/ui/unnamed_argument_mode.rs deleted file mode 100644 index 2014e0d23d849..0000000000000 --- a/tests/ui/unnamed_argument_mode.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass - -fn good(_a: &isize) { -} - -// unnamed argument &isize is now parse x: &isize - -fn called(_f: F) where F: FnOnce(&isize) { -} - -pub fn main() { - called(good); -} diff --git a/tests/ui/unpretty/frontmatter.rs b/tests/ui/unpretty/frontmatter.rs new file mode 100644 index 0000000000000..1971808e2a866 --- /dev/null +++ b/tests/ui/unpretty/frontmatter.rs @@ -0,0 +1,10 @@ +--- +--- + +//@ compile-flags: -Zunpretty=normal +//@ check-pass + +#![feature(frontmatter)] + +fn main() { +} diff --git a/tests/ui/unpretty/frontmatter.stdout b/tests/ui/unpretty/frontmatter.stdout new file mode 100644 index 0000000000000..2ccbb1b258255 --- /dev/null +++ b/tests/ui/unpretty/frontmatter.stdout @@ -0,0 +1,9 @@ +--- +--- + +//@ compile-flags: -Zunpretty=normal +//@ check-pass + +#![feature(frontmatter)] + +fn main() {} diff --git a/tests/ui/unreachable-code-1.rs b/tests/ui/unreachable-code-1.rs deleted file mode 100644 index 9c5f7c8f45190..0000000000000 --- a/tests/ui/unreachable-code-1.rs +++ /dev/null @@ -1,19 +0,0 @@ -//@ run-pass - -#![allow(unused_must_use)] -#![allow(unreachable_code)] - -#![allow(unused_variables)] -#![allow(dead_code)] - -fn id(x: bool) -> bool { x } - -fn call_id() { - let c = panic!(); - id(c); -} - -fn call_id_3() { id(return) && id(return); } - -pub fn main() { -} diff --git a/tests/ui/uninit-empty-types.rs b/tests/ui/unsafe/maybe-uninit-zero-sized-types.rs similarity index 61% rename from tests/ui/uninit-empty-types.rs rename to tests/ui/unsafe/maybe-uninit-zero-sized-types.rs index 82474d873b788..e587ca554fe4d 100644 --- a/tests/ui/uninit-empty-types.rs +++ b/tests/ui/unsafe/maybe-uninit-zero-sized-types.rs @@ -1,6 +1,9 @@ -//@ build-pass -// Test the uninit() construct returning various empty types. +//! This test checks that ZSTs can be safely initialized from +//! `MaybeUninit::uninit().assume_init()` and `std::mem::uninitialized()` +//! (which is deprecated). This is safe because ZSTs inherently +//! require no actual memory initialization, as they occupy no memory. +//@ build-pass use std::mem::MaybeUninit; diff --git a/tests/ui/unused-move.rs b/tests/ui/unused-move.rs deleted file mode 100644 index 3d5eff2c48d50..0000000000000 --- a/tests/ui/unused-move.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass -// Issue #3878 -// Issue Name: Unused move causes a crash -// Abstract: zero-fill to block after drop - - -#![allow(path_statements)] - -pub fn main() { - let y: Box<_> = Box::new(1); - y; -} diff --git a/tests/ui/use-import-export.rs b/tests/ui/use-import-export.rs deleted file mode 100644 index d948ffc1520b3..0000000000000 --- a/tests/ui/use-import-export.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-pass - -mod foo { - pub fn x() -> isize { return 1; } -} - -mod bar { - pub fn y() -> isize { return 1; } -} - -pub fn main() { foo::x(); bar::y(); } diff --git a/tests/ui/use-module-level-int-consts.rs b/tests/ui/use-module-level-int-consts.rs deleted file mode 100644 index 6e8c7053c5760..0000000000000 --- a/tests/ui/use-module-level-int-consts.rs +++ /dev/null @@ -1,12 +0,0 @@ -//@ run-pass - -// Make sure the module level constants are still there and accessible even after -// the corresponding associated constants have been added, and later stabilized. -#![allow(deprecated, deprecated_in_future)] -use std::{u16, f32}; - -fn main() { - let _ = u16::MAX; - let _ = f32::EPSILON; - let _ = std::f64::MANTISSA_DIGITS; -} diff --git a/tests/ui/walk-struct-literal-with.rs b/tests/ui/walk-struct-literal-with.rs deleted file mode 100644 index ee1a77eb9a48a..0000000000000 --- a/tests/ui/walk-struct-literal-with.rs +++ /dev/null @@ -1,17 +0,0 @@ -struct Mine{ - test: String, - other_val: isize -} - -impl Mine{ - fn make_string_bar(mut self) -> Mine{ - self.test = "Bar".to_string(); - self - } -} - -fn main(){ - let start = Mine{test:"Foo".to_string(), other_val:0}; - let end = Mine{other_val:1, ..start.make_string_bar()}; - println!("{}", start.test); //~ ERROR borrow of moved value: `start` -} diff --git a/tests/ui/weak-new-uninhabited-issue-48493.rs b/tests/ui/weak-new-uninhabited-issue-48493.rs deleted file mode 100644 index ce7d5786b41bb..0000000000000 --- a/tests/ui/weak-new-uninhabited-issue-48493.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ run-pass - -fn main() { - enum Void {} - let _ = std::rc::Weak::::new(); - let _ = std::sync::Weak::::new(); -} diff --git a/tests/ui/weird-exit-code.rs b/tests/ui/weird-exit-code.rs deleted file mode 100644 index e016343f8ba2f..0000000000000 --- a/tests/ui/weird-exit-code.rs +++ /dev/null @@ -1,28 +0,0 @@ -//@ run-pass -// On Windows the GetExitCodeProcess API is used to get the exit code of a -// process, but it's easy to mistake a process exiting with the code 259 as -// "still running" because this is the value of the STILL_ACTIVE constant. Make -// sure we handle this case in the standard library and correctly report the -// status. -// -// Note that this is disabled on unix as processes exiting with 259 will have -// their exit status truncated to 3 (only the lower 8 bits are used). - -#[cfg(windows)] -fn main() { - use std::process::{self, Command}; - use std::env; - - if env::args().len() == 1 { - let status = Command::new(env::current_exe().unwrap()) - .arg("foo") - .status() - .unwrap(); - assert_eq!(status.code(), Some(259)); - } else { - process::exit(259); - } -} - -#[cfg(not(windows))] -fn main() {}