diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 56ef609612ac0..4b730d307fd6c 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -352,10 +352,10 @@ fn check_occurrences( check_ops_is_prefix(psess, node_id, macros, binders, ops, span, name); } TokenTree::MetaVarExpr(dl, ref mve) => { - let Some(name) = mve.ident().map(MacroRulesNormalizedIdent::new) else { - return; - }; - check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name); + mve.for_each_metavar((), |_, ident| { + let name = MacroRulesNormalizedIdent::new(*ident); + check_ops_is_prefix(psess, node_id, macros, binders, ops, dl.entire(), name); + }); } TokenTree::Delimited(.., ref del) => { check_nested_occurrences(psess, node_id, &del.tts, macros, binders, ops, guar); diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 2964ac8cc5854..c4ba98f581e49 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -111,10 +111,18 @@ impl MetaVarExpr { Ok(rslt) } - pub(crate) fn ident(&self) -> Option { - match *self { - MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident), - MetaVarExpr::Concat { .. } | MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None, + pub(crate) fn for_each_metavar(&self, mut aux: A, mut cb: impl FnMut(A, &Ident) -> A) -> A { + match self { + MetaVarExpr::Concat(elems) => { + for elem in elems { + if let MetaVarExprConcatElem::Var(ident) = elem { + aux = cb(aux, ident) + } + } + aux + } + MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => cb(aux, ident), + MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => aux, } } } diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index 7e2ea8de5fca2..62337756cd880 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -557,17 +557,13 @@ fn lockstep_iter_size( } } TokenTree::MetaVarExpr(_, expr) => { - let default_rslt = LockstepIterSize::Unconstrained; - let Some(ident) = expr.ident() else { - return default_rslt; - }; - let name = MacroRulesNormalizedIdent::new(ident); - match lookup_cur_matched(name, interpolations, repeats) { - Some(MatchedSeq(ads)) => { - default_rslt.with(LockstepIterSize::Constraint(ads.len(), name)) - } - _ => default_rslt, - } + expr.for_each_metavar(LockstepIterSize::Unconstrained, |lis, ident| { + lis.with(lockstep_iter_size( + &TokenTree::MetaVar(ident.span, *ident), + interpolations, + repeats, + )) + }) } TokenTree::Token(..) => LockstepIterSize::Unconstrained, } @@ -695,7 +691,23 @@ fn transcribe_metavar_expr<'a>( let symbol = match element { MetaVarExprConcatElem::Ident(elem) => elem.name, MetaVarExprConcatElem::Literal(elem) => *elem, - MetaVarExprConcatElem::Var(elem) => extract_var_symbol(dcx, *elem, interp)?, + MetaVarExprConcatElem::Var(ident) => { + match matched_from_ident(dcx, *ident, interp)? { + NamedMatch::MatchedSeq(named_matches) => { + let curr_idx = repeats.last().unwrap().0; + match &named_matches[curr_idx] { + // FIXME(c410-f3r) Nested repetitions are unimplemented + MatchedSeq(_) => unimplemented!(), + MatchedSingle(pnr) => { + extract_symbol_from_pnr(dcx, pnr, ident.span)? + } + } + } + NamedMatch::MatchedSingle(pnr) => { + extract_symbol_from_pnr(dcx, pnr, ident.span)? + } + } + } }; concatenated.push_str(symbol.as_str()); } @@ -752,41 +764,48 @@ fn transcribe_metavar_expr<'a>( } /// Extracts an metavariable symbol that can be an identifier, a token tree or a literal. -fn extract_var_symbol<'a>( +fn extract_symbol_from_pnr<'a>( dcx: DiagCtxtHandle<'a>, - ident: Ident, - interp: &FxHashMap, + pnr: &ParseNtResult, + span_err: Span, ) -> PResult<'a, Symbol> { - if let NamedMatch::MatchedSingle(pnr) = matched_from_ident(dcx, ident, interp)? { - if let ParseNtResult::Ident(nt_ident, is_raw) = pnr { + match pnr { + ParseNtResult::Ident(nt_ident, is_raw) => { if let IdentIsRaw::Yes = is_raw { - return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); + return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR)); } return Ok(nt_ident.name); } - - if let ParseNtResult::Tt(TokenTree::Token(Token { kind, .. }, _)) = pnr { - if let TokenKind::Ident(symbol, is_raw) = kind { - if let IdentIsRaw::Yes = is_raw { - return Err(dcx.struct_span_err(ident.span, RAW_IDENT_ERR)); - } - return Ok(*symbol); - } - - if let TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }) = kind { - return Ok(*symbol); + ParseNtResult::Tt(TokenTree::Token( + Token { kind: TokenKind::Ident(symbol, is_raw), .. }, + _, + )) => { + if let IdentIsRaw::Yes = is_raw { + return Err(dcx.struct_span_err(span_err, RAW_IDENT_ERR)); } + return Ok(*symbol); } - - if let ParseNtResult::Nt(nt) = pnr - && let Nonterminal::NtLiteral(expr) = &**nt - && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = &expr.kind + ParseNtResult::Tt(TokenTree::Token( + Token { + kind: TokenKind::Literal(Lit { kind: LitKind::Str, symbol, suffix: None }), + .. + }, + _, + )) => { + return Ok(*symbol); + } + ParseNtResult::Nt(nt) + if let Nonterminal::NtLiteral(expr) = &**nt + && let ExprKind::Lit(Lit { kind: LitKind::Str, symbol, suffix: None }) = + &expr.kind => { return Ok(*symbol); } + _ => Err(dcx + .struct_err( + "metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`", + ) + .with_note("currently only string literals are supported") + .with_span(span_err)), } - Err(dcx - .struct_err("metavariables of `${concat(..)}` must be of type `ident`, `literal` or `tt`") - .with_note("currently only string literals are supported") - .with_span(ident.span)) } diff --git a/library/std/src/sys/pal/windows/c.rs b/library/std/src/sys/pal/windows/c.rs index 296d19a926d96..84f3d6a5399bc 100644 --- a/library/std/src/sys/pal/windows/c.rs +++ b/library/std/src/sys/pal/windows/c.rs @@ -8,7 +8,7 @@ use crate::ffi::CStr; use crate::mem; -use crate::os::raw::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void}; +use crate::os::raw::{c_uint, c_ulong, c_ushort, c_void}; use crate::os::windows::io::{AsRawHandle, BorrowedHandle}; use crate::ptr; @@ -19,12 +19,6 @@ pub use windows_sys::*; pub type WCHAR = u16; -pub type socklen_t = c_int; -pub type ADDRESS_FAMILY = c_ushort; -pub use FD_SET as fd_set; -pub use LINGER as linger; -pub use TIMEVAL as timeval; - pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::without_provenance_mut(-1i32 as _); // https://learn.microsoft.com/en-us/cpp/c-runtime-library/exit-success-exit-failure?view=msvc-170 @@ -42,20 +36,6 @@ pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() }; pub const OBJ_DONT_REPARSE: u32 = windows_sys::OBJ_DONT_REPARSE as u32; pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: u32 = windows_sys::FRS_ERR_SYSVOL_POPULATE_TIMEOUT as u32; -pub const AF_INET: c_int = windows_sys::AF_INET as c_int; -pub const AF_INET6: c_int = windows_sys::AF_INET6 as c_int; - -#[repr(C)] -pub struct ip_mreq { - pub imr_multiaddr: in_addr, - pub imr_interface: in_addr, -} - -#[repr(C)] -pub struct ipv6_mreq { - pub ipv6mr_multiaddr: in6_addr, - pub ipv6mr_interface: c_uint, -} // Equivalent to the `NT_SUCCESS` C preprocessor macro. // See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values @@ -127,45 +107,6 @@ pub struct MOUNT_POINT_REPARSE_BUFFER { pub PathBuffer: WCHAR, } -#[repr(C)] -pub struct SOCKADDR_STORAGE_LH { - pub ss_family: ADDRESS_FAMILY, - pub __ss_pad1: [c_char; 6], - pub __ss_align: i64, - pub __ss_pad2: [c_char; 112], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in { - pub sin_family: ADDRESS_FAMILY, - pub sin_port: c_ushort, - pub sin_addr: in_addr, - pub sin_zero: [c_char; 8], -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct sockaddr_in6 { - pub sin6_family: ADDRESS_FAMILY, - pub sin6_port: c_ushort, - pub sin6_flowinfo: c_ulong, - pub sin6_addr: in6_addr, - pub sin6_scope_id: c_ulong, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in_addr { - pub s_addr: u32, -} - -#[repr(C)] -#[derive(Copy, Clone)] -pub struct in6_addr { - pub s6_addr: [u8; 16], -} - // Desktop specific functions & types cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { @@ -205,42 +146,6 @@ pub unsafe extern "system" fn ReadFileEx( ) } -// POSIX compatibility shims. -pub unsafe fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int { - windows_sys::recv(socket, buf.cast::(), len, flags) -} -pub unsafe fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int { - windows_sys::send(socket, buf.cast::(), len, flags) -} -pub unsafe fn recvfrom( - socket: SOCKET, - buf: *mut c_void, - len: c_int, - flags: c_int, - addr: *mut SOCKADDR, - addrlen: *mut c_int, -) -> c_int { - windows_sys::recvfrom(socket, buf.cast::(), len, flags, addr, addrlen) -} -pub unsafe fn sendto( - socket: SOCKET, - buf: *const c_void, - len: c_int, - flags: c_int, - addr: *const SOCKADDR, - addrlen: c_int, -) -> c_int { - windows_sys::sendto(socket, buf.cast::(), len, flags, addr, addrlen) -} -pub unsafe fn getaddrinfo( - node: *const c_char, - service: *const c_char, - hints: *const ADDRINFOA, - res: *mut *mut ADDRINFOA, -) -> c_int { - windows_sys::getaddrinfo(node.cast::(), service.cast::(), hints, res) -} - cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { pub unsafe fn NtReadFile( diff --git a/library/std/src/sys/pal/windows/c/bindings.txt b/library/std/src/sys/pal/windows/c/bindings.txt index 5ad4a3731d822..794e2c90c5242 100644 --- a/library/std/src/sys/pal/windows/c/bindings.txt +++ b/library/std/src/sys/pal/windows/c/bindings.txt @@ -2059,6 +2059,7 @@ Windows.Win32.Networking.WinSock.SOCK_RDM Windows.Win32.Networking.WinSock.SOCK_SEQPACKET Windows.Win32.Networking.WinSock.SOCK_STREAM Windows.Win32.Networking.WinSock.SOCKADDR +Windows.Win32.Networking.WinSock.SOCKADDR_STORAGE Windows.Win32.Networking.WinSock.SOCKADDR_UN Windows.Win32.Networking.WinSock.SOCKET Windows.Win32.Networking.WinSock.SOCKET_ERROR diff --git a/library/std/src/sys/pal/windows/c/windows_sys.rs b/library/std/src/sys/pal/windows/c/windows_sys.rs index fea00fec9ae59..eae0f77586066 100644 --- a/library/std/src/sys/pal/windows/c/windows_sys.rs +++ b/library/std/src/sys/pal/windows/c/windows_sys.rs @@ -2890,6 +2890,14 @@ pub struct SOCKADDR { } #[repr(C)] #[derive(Clone, Copy)] +pub struct SOCKADDR_STORAGE { + pub ss_family: ADDRESS_FAMILY, + pub __ss_pad1: [i8; 6], + pub __ss_align: i64, + pub __ss_pad2: [i8; 112], +} +#[repr(C)] +#[derive(Clone, Copy)] pub struct SOCKADDR_UN { pub sun_family: ADDRESS_FAMILY, pub sun_path: [i8; 108], diff --git a/library/std/src/sys/pal/windows/net.rs b/library/std/src/sys/pal/windows/net.rs index d51fb56238f2c..b7ecff032e4af 100644 --- a/library/std/src/sys/pal/windows/net.rs +++ b/library/std/src/sys/pal/windows/net.rs @@ -17,14 +17,100 @@ use crate::time::Duration; use core::ffi::{c_int, c_long, c_ulong, c_ushort}; +#[allow(non_camel_case_types)] pub type wrlen_t = i32; pub mod netc { - pub use crate::sys::c::ADDRESS_FAMILY as sa_family_t; - pub use crate::sys::c::ADDRINFOA as addrinfo; - pub use crate::sys::c::SOCKADDR as sockaddr; - pub use crate::sys::c::SOCKADDR_STORAGE_LH as sockaddr_storage; - pub use crate::sys::c::*; + //! BSD socket compatibility shim + //! + //! Some Windows API types are not quite what's expected by our cross-platform + //! net code. E.g. naming differences or different pointer types. + use crate::sys::c::{self, ADDRESS_FAMILY, ADDRINFOA, SOCKADDR, SOCKET}; + use core::ffi::{c_char, c_int, c_uint, c_ulong, c_ushort, c_void}; + + // re-exports from Windows API bindings. + pub use crate::sys::c::{ + bind, connect, freeaddrinfo, getpeername, getsockname, getsockopt, listen, setsockopt, + ADDRESS_FAMILY as sa_family_t, ADDRINFOA as addrinfo, IPPROTO_IP, IPPROTO_IPV6, + IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP, IPV6_MULTICAST_LOOP, IPV6_V6ONLY, + IP_ADD_MEMBERSHIP, IP_DROP_MEMBERSHIP, IP_MULTICAST_LOOP, IP_MULTICAST_TTL, IP_TTL, + SOCKADDR as sockaddr, SOCKADDR_STORAGE as sockaddr_storage, SOCK_DGRAM, SOCK_STREAM, + SOL_SOCKET, SO_BROADCAST, SO_RCVTIMEO, SO_SNDTIMEO, + }; + + #[allow(non_camel_case_types)] + pub type socklen_t = c_int; + + pub const AF_INET: i32 = c::AF_INET as i32; + pub const AF_INET6: i32 = c::AF_INET6 as i32; + + // The following two structs use a union in the generated bindings but + // our cross-platform code expects a normal field so it's redefined here. + // As a consequence, we also need to redefine other structs that use this struct. + #[repr(C)] + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[repr(C)] + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + #[repr(C)] + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: ADDRESS_FAMILY, + pub sin_port: c_ushort, + pub sin_addr: in_addr, + pub sin_zero: [c_char; 8], + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: ADDRESS_FAMILY, + pub sin6_port: c_ushort, + pub sin6_flowinfo: c_ulong, + pub sin6_addr: in6_addr, + pub sin6_scope_id: c_ulong, + } + + pub unsafe fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int { + unsafe { c::send(socket, buf.cast::(), len, flags) } + } + pub unsafe fn sendto( + socket: SOCKET, + buf: *const c_void, + len: c_int, + flags: c_int, + addr: *const SOCKADDR, + addrlen: c_int, + ) -> c_int { + unsafe { c::sendto(socket, buf.cast::(), len, flags, addr, addrlen) } + } + pub unsafe fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const ADDRINFOA, + res: *mut *mut ADDRINFOA, + ) -> c_int { + unsafe { c::getaddrinfo(node.cast::(), service.cast::(), hints, res) } + } } pub struct Socket(OwnedSocket); @@ -102,8 +188,8 @@ where impl Socket { pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result { let family = match *addr { - SocketAddr::V4(..) => c::AF_INET, - SocketAddr::V6(..) => c::AF_INET6, + SocketAddr::V4(..) => netc::AF_INET, + SocketAddr::V6(..) => netc::AF_INET6, }; let socket = unsafe { c::WSASocketW( @@ -157,7 +243,7 @@ impl Socket { return Err(io::Error::ZERO_TIMEOUT); } - let mut timeout = c::timeval { + let mut timeout = c::TIMEVAL { tv_sec: cmp::min(timeout.as_secs(), c_long::MAX as u64) as c_long, tv_usec: timeout.subsec_micros() as c_long, }; @@ -167,7 +253,7 @@ impl Socket { } let fds = { - let mut fds = unsafe { mem::zeroed::() }; + let mut fds = unsafe { mem::zeroed::() }; fds.fd_count = 1; fds.fd_array[0] = self.as_raw(); fds @@ -295,8 +381,8 @@ impl Socket { buf: &mut [u8], flags: c_int, ) -> io::Result<(usize, SocketAddr)> { - let mut storage = unsafe { mem::zeroed::() }; - let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; + let mut storage = unsafe { mem::zeroed::() }; + let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t; let length = cmp::min(buf.len(), ::MAX as usize) as wrlen_t; // On unix when a socket is shut down all further reads return 0, so we @@ -399,7 +485,7 @@ impl Socket { } pub fn set_linger(&self, linger: Option) -> io::Result<()> { - let linger = c::linger { + let linger = c::LINGER { l_onoff: linger.is_some() as c_ushort, l_linger: linger.unwrap_or_default().as_secs() as c_ushort, }; @@ -408,7 +494,7 @@ impl Socket { } pub fn linger(&self) -> io::Result> { - let val: c::linger = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; + let val: c::LINGER = net::getsockopt(self, c::SOL_SOCKET, c::SO_LINGER)?; Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64))) } diff --git a/library/std/src/sys/thread_local/guard/windows.rs b/library/std/src/sys/thread_local/guard/windows.rs index f6cd457046ffc..e08ac44e1af88 100644 --- a/library/std/src/sys/thread_local/guard/windows.rs +++ b/library/std/src/sys/thread_local/guard/windows.rs @@ -78,19 +78,6 @@ pub fn enable() { pub static CALLBACK: unsafe extern "system" fn(*mut c_void, u32, *mut c_void) = tls_callback; unsafe extern "system" fn tls_callback(_h: *mut c_void, dw_reason: u32, _pv: *mut c_void) { - // See comments above for what this is doing. Note that we don't need this - // trickery on GNU windows, just on MSVC. - #[cfg(all(target_env = "msvc", not(target_thread_local)))] - { - extern "C" { - static _tls_used: u8; - } - - unsafe { - ptr::from_ref(&_tls_used).read_volatile(); - } - } - if dw_reason == c::DLL_THREAD_DETACH || dw_reason == c::DLL_PROCESS_DETACH { #[cfg(target_thread_local)] unsafe { diff --git a/src/ci/run.sh b/src/ci/run.sh index 869f75e923d2c..c8201d9bcfd27 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -19,7 +19,7 @@ if [ "$NO_CHANGE_USER" = "" ]; then # already be running with the right user. # # For NO_CHANGE_USER done in the small number of Dockerfiles affected. - echo -e '[safe]\n\tdirectory = *' > /home/user/gitconfig + echo -e '[safe]\n\tdirectory = *' > /home/user/.gitconfig exec su --preserve-environment -c "env PATH=$PATH \"$0\"" user fi diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 0097386591529..9256330ac7c46 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -2062,16 +2062,23 @@ pub(super) fn item_path(ty: ItemType, name: &str) -> String { fn bounds(t_bounds: &[clean::GenericBound], trait_alias: bool, cx: &Context<'_>) -> String { let mut bounds = String::new(); - if !t_bounds.is_empty() { - if !trait_alias { + if t_bounds.is_empty() { + return bounds; + } + let has_lots_of_bounds = t_bounds.len() > 2; + let inter_str = if has_lots_of_bounds { "\n + " } else { " + " }; + if !trait_alias { + if has_lots_of_bounds { + bounds.push_str(":\n "); + } else { bounds.push_str(": "); } - for (i, p) in t_bounds.iter().enumerate() { - if i > 0 { - bounds.push_str(" + "); - } - bounds.push_str(&p.print(cx).to_string()); + } + for (i, p) in t_bounds.iter().enumerate() { + if i > 0 { + bounds.push_str(inter_str); } + bounds.push_str(&p.print(cx).to_string()); } bounds } diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index a2e7907b532e4..e0bea5f053d9f 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -157,6 +157,7 @@ static TARGETS: &[&str] = &[ "wasm32-wasi", "wasm32-wasip1", "wasm32-wasip1-threads", + "wasm32-wasip2", "x86_64-apple-darwin", "x86_64-apple-ios", "x86_64-fortanix-unknown-sgx", diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index da7f03441e72f..bc66dcbfb944e 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -760,8 +760,14 @@ pub fn output_testname_unique( /// test/revision should reside. Example: /// /path/to/build/host-triple/test/ui/relative/testname.revision.mode/ pub fn output_base_dir(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { - output_relative_path(config, &testpaths.relative_dir) - .join(output_testname_unique(config, testpaths, revision)) + // In run-make tests, constructing a relative path + unique testname causes a double layering + // since revisions are not supported, causing unnecessary nesting. + if config.mode == Mode::RunMake { + output_relative_path(config, &testpaths.relative_dir) + } else { + output_relative_path(config, &testpaths.relative_dir) + .join(output_testname_unique(config, testpaths, revision)) + } } /// Absolute path to the base filename used as output for the given diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 0122886961737..5398820313648 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -3433,29 +3433,51 @@ impl<'test> TestCx<'test> { fn run_rmake_v2_test(&self) { // For `run-make` V2, we need to perform 2 steps to build and run a `run-make` V2 recipe - // (`rmake.rs`) to run the actual tests. The support library is already built as a tool - // dylib and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`. + // (`rmake.rs`) to run the actual tests. The support library is already built as a tool rust + // library and is available under `build/$TARGET/stageN-tools-bin/librun_make_support.rlib`. // - // 1. We need to build the recipe `rmake.rs` and link in the support library. - // 2. We need to run the recipe to build and run the tests. - let cwd = env::current_dir().unwrap(); - let src_root = self.config.src_base.parent().unwrap().parent().unwrap(); - let src_root = cwd.join(&src_root); - let build_root = self.config.build_base.parent().unwrap().parent().unwrap(); - let build_root = cwd.join(&build_root); + // 1. We need to build the recipe `rmake.rs` as a binary and link in the `run_make_support` + // library. + // 2. We need to run the recipe binary. + + // So we assume the rust-lang/rust project setup looks like the following (our `.` is the + // top-level directory, irrelevant entries to our purposes omitted): + // + // ``` + // . // <- `source_root` + // ├── build/ // <- `build_root` + // ├── compiler/ + // ├── library/ + // ├── src/ + // │ └── tools/ + // │ └── run_make_support/ + // └── tests + // └── run-make/ + // ``` + + // `source_root` is the top-level directory containing the rust-lang/rust checkout. + let source_root = + self.config.find_rust_src_root().expect("could not determine rust source root"); + // `self.config.build_base` is actually the build base folder + "test" + test suite name, it + // looks like `build//test/run-make`. But we want `build//`. Note + // that the `build` directory does not need to be called `build`, nor does it need to be + // under `source_root`, so we must compute it based off of `self.config.build_base`. + let build_root = + self.config.build_base.parent().and_then(Path::parent).unwrap().to_path_buf(); // We construct the following directory tree for each rmake.rs test: // ``` - // base_dir/ + // / // rmake.exe // rmake_out/ // ``` - // having the executable separate from the output artifacts directory allows the recipes to - // `remove_dir_all($TMPDIR)` without running into permission denied issues because - // the executable is not under the `rmake_out/` directory. + // having the recipe executable separate from the output artifacts directory allows the + // recipes to `remove_dir_all($TMPDIR)` without running into issues related trying to remove + // a currently running executable because the recipe executable is not under the + // `rmake_out/` directory. // // This setup intentionally diverges from legacy Makefile run-make tests. - let base_dir = cwd.join(self.output_base_name()); + let base_dir = self.output_base_name(); if base_dir.exists() { self.aggressive_rm_rf(&base_dir).unwrap(); } @@ -3477,120 +3499,186 @@ impl<'test> TestCx<'test> { } } - // HACK: assume stageN-target, we only want stageN. + // `self.config.stage_id` looks like `stage1-`, but we only want + // the `stage1` part as that is what the output directories of bootstrap are prefixed with. + // Note that this *assumes* build layout from bootstrap is produced as: + // + // ``` + // build// // <- this is `build_root` + // ├── stage0 + // ├── stage0-bootstrap-tools + // ├── stage0-codegen + // ├── stage0-rustc + // ├── stage0-std + // ├── stage0-sysroot + // ├── stage0-tools + // ├── stage0-tools-bin + // ├── stage1 + // ├── stage1-std + // ├── stage1-tools + // ├── stage1-tools-bin + // └── test + // ``` + // FIXME(jieyouxu): improve the communication between bootstrap and compiletest here so + // we don't have to hack out a `stageN`. let stage = self.config.stage_id.split('-').next().unwrap(); - // First, we construct the path to the built support library. - let mut support_lib_path = PathBuf::new(); - support_lib_path.push(&build_root); - support_lib_path.push(format!("{}-tools-bin", stage)); - support_lib_path.push("librun_make_support.rlib"); + // In order to link in the support library as a rlib when compiling recipes, we need three + // paths: + // 1. Path of the built support library rlib itself. + // 2. Path of the built support library's dependencies directory. + // 3. Path of the built support library's dependencies' dependencies directory. + // + // The paths look like + // + // ``` + // build// + // ├── stageN-tools-bin/ + // │ └── librun_make_support.rlib // <- support rlib itself + // ├── stageN-tools/ + // │ ├── release/deps/ // <- deps of deps + // │ └── /release/deps/ // <- deps + // ``` + // + // FIXME(jieyouxu): there almost certainly is a better way to do this (specifically how the + // support lib and its deps are organized, can't we copy them to the tools-bin dir as + // well?), but this seems to work for now. - let mut stage_std_path = PathBuf::new(); - stage_std_path.push(&build_root); - stage_std_path.push(&stage); - stage_std_path.push("lib"); + let stage_tools_bin = build_root.join(format!("{stage}-tools-bin")); + let support_lib_path = stage_tools_bin.join("librun_make_support.rlib"); - // Then, we need to build the recipe `rmake.rs` and link in the support library. - let recipe_bin = base_dir.join(if self.config.target.contains("windows") { - "rmake.exe" - } else { - "rmake" - }); - - let mut support_lib_deps = PathBuf::new(); - support_lib_deps.push(&build_root); - support_lib_deps.push(format!("{}-tools", stage)); - support_lib_deps.push(&self.config.host); - support_lib_deps.push("release"); - support_lib_deps.push("deps"); - - let mut support_lib_deps_deps = PathBuf::new(); - support_lib_deps_deps.push(&build_root); - support_lib_deps_deps.push(format!("{}-tools", stage)); - support_lib_deps_deps.push("release"); - support_lib_deps_deps.push("deps"); - - debug!(?support_lib_deps); - debug!(?support_lib_deps_deps); - - let orig_dylib_env_paths = + let stage_tools = build_root.join(format!("{stage}-tools")); + let support_lib_deps = stage_tools.join(&self.config.host).join("release").join("deps"); + let support_lib_deps_deps = stage_tools.join("release").join("deps"); + + // To compile the recipe with rustc, we need to provide suitable dynamic library search + // paths to rustc. This includes both: + // 1. The "base" dylib search paths that was provided to compiletest, e.g. `LD_LIBRARY_PATH` + // on some linux distros. + // 2. Specific library paths in `self.config.compile_lib_path` needed for running rustc. + + let base_dylib_search_paths = Vec::from_iter(env::split_paths(&env::var(dylib_env_var()).unwrap())); - let mut host_dylib_env_paths = Vec::new(); - host_dylib_env_paths.push(cwd.join(&self.config.compile_lib_path)); - host_dylib_env_paths.extend(orig_dylib_env_paths.iter().cloned()); - let host_dylib_env_paths = env::join_paths(host_dylib_env_paths).unwrap(); + let host_dylib_search_paths = { + let mut paths = vec![self.config.compile_lib_path.clone()]; + paths.extend(base_dylib_search_paths.iter().cloned()); + paths + }; + + // Calculate the paths of the recipe binary. As previously discussed, this is placed at + // `/` with `bin_name` being `rmake` or `rmake.exe` depending on + // platform. + let recipe_bin = { + let mut p = base_dir.join("rmake"); + p.set_extension(env::consts::EXE_EXTENSION); + p + }; - let mut cmd = Command::new(&self.config.rustc_path); - cmd.arg("-o") + let mut rustc = Command::new(&self.config.rustc_path); + rustc + .arg("-o") .arg(&recipe_bin) + // Specify library search paths for `run_make_support`. .arg(format!("-Ldependency={}", &support_lib_path.parent().unwrap().to_string_lossy())) .arg(format!("-Ldependency={}", &support_lib_deps.to_string_lossy())) .arg(format!("-Ldependency={}", &support_lib_deps_deps.to_string_lossy())) + // Provide `run_make_support` as extern prelude, so test writers don't need to write + // `extern run_make_support;`. .arg("--extern") .arg(format!("run_make_support={}", &support_lib_path.to_string_lossy())) .arg("--edition=2021") .arg(&self.testpaths.file.join("rmake.rs")) - .env("TARGET", &self.config.target) - .env("PYTHON", &self.config.python) - .env("RUST_BUILD_STAGE", &self.config.stage_id) - .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) - .env(dylib_env_var(), &host_dylib_env_paths) - .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) - .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) - .env("LLVM_COMPONENTS", &self.config.llvm_components); + // Provide necessary library search paths for rustc. + .env(dylib_env_var(), &env::join_paths(host_dylib_search_paths).unwrap()); // In test code we want to be very pedantic about values being silently discarded that are // annotated with `#[must_use]`. - cmd.arg("-Dunused_must_use"); - + rustc.arg("-Dunused_must_use"); + + // > `cg_clif` uses `COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0` for running the rustc + // > test suite. With the introduction of rmake.rs this broke. `librun_make_support.rlib` is + // > compiled using the bootstrap rustc wrapper which sets `--sysroot + // > build/aarch64-unknown-linux-gnu/stage0-sysroot`, but then compiletest will compile + // > `rmake.rs` using the sysroot of the bootstrap compiler causing it to not find the + // > `libstd.rlib` against which `librun_make_support.rlib` is compiled. + // + // The gist here is that we have to pass the proper stage0 sysroot if we want + // + // ``` + // $ COMPILETEST_FORCE_STAGE0=1 ./x test run-make --stage 0 + // ``` + // + // to work correctly. + // + // See for more background. if std::env::var_os("COMPILETEST_FORCE_STAGE0").is_some() { - let mut stage0_sysroot = build_root.clone(); - stage0_sysroot.push("stage0-sysroot"); - debug!(?stage0_sysroot); - debug!(exists = stage0_sysroot.exists()); - - cmd.arg("--sysroot").arg(&stage0_sysroot); + let stage0_sysroot = build_root.join("stage0-sysroot"); + rustc.arg("--sysroot").arg(&stage0_sysroot); } - let res = self.run_command_to_procres(&mut cmd); + // Now run rustc to build the recipe. + let res = self.run_command_to_procres(&mut rustc); if !res.status.success() { self.fatal_proc_rec("run-make test failed: could not build `rmake.rs` recipe", &res); } - // Finally, we need to run the recipe binary to build and run the actual tests. - debug!(?recipe_bin); + // To actually run the recipe, we have to provide the recipe with a bunch of information + // provided through env vars. + + // Compute stage-specific standard library paths. + let stage_std_path = build_root.join(&stage).join("lib"); - let mut dylib_env_paths = orig_dylib_env_paths.clone(); - dylib_env_paths.push(support_lib_path.parent().unwrap().to_path_buf()); - dylib_env_paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib")); - let dylib_env_paths = env::join_paths(dylib_env_paths).unwrap(); + // Compute dynamic library search paths for recipes. + let recipe_dylib_search_paths = { + let mut paths = base_dylib_search_paths.clone(); + paths.push(support_lib_path.parent().unwrap().to_path_buf()); + paths.push(stage_std_path.join("rustlib").join(&self.config.host).join("lib")); + paths + }; - let mut target_rpath_env_path = Vec::new(); - target_rpath_env_path.push(&rmake_out_dir); - target_rpath_env_path.extend(&orig_dylib_env_paths); - let target_rpath_env_path = env::join_paths(target_rpath_env_path).unwrap(); + // Compute runtime library search paths for recipes. This is target-specific. + let target_runtime_dylib_search_paths = { + let mut paths = vec![rmake_out_dir.clone()]; + paths.extend(base_dylib_search_paths.iter().cloned()); + paths + }; + // FIXME(jieyouxu): please rename `TARGET_RPATH_ENV`, `HOST_RPATH_DIR` and + // `TARGET_RPATH_DIR`, it is **extremely** confusing! let mut cmd = Command::new(&recipe_bin); cmd.current_dir(&rmake_out_dir) .stdout(Stdio::piped()) .stderr(Stdio::piped()) + // Provide the target-specific env var that is used to record dylib search paths. For + // example, this could be `LD_LIBRARY_PATH` on some linux distros but `PATH` on Windows. .env("LD_LIB_PATH_ENVVAR", dylib_env_var()) - .env("TARGET_RPATH_ENV", &target_rpath_env_path) - .env(dylib_env_var(), &dylib_env_paths) + // Provide the dylib search paths. + .env(dylib_env_var(), &env::join_paths(recipe_dylib_search_paths).unwrap()) + // Provide runtime dylib search paths. + .env("TARGET_RPATH_ENV", &env::join_paths(target_runtime_dylib_search_paths).unwrap()) + // Provide the target. .env("TARGET", &self.config.target) + // Some tests unfortunately still need Python, so provide path to a Python interpreter. .env("PYTHON", &self.config.python) - .env("SOURCE_ROOT", &src_root) - .env("RUST_BUILD_STAGE", &self.config.stage_id) - .env("RUSTC", cwd.join(&self.config.rustc_path)) - .env("HOST_RPATH_DIR", cwd.join(&self.config.compile_lib_path)) - .env("TARGET_RPATH_DIR", cwd.join(&self.config.run_lib_path)) + // Provide path to checkout root. This is the top-level directory containing + // rust-lang/rust checkout. + .env("SOURCE_ROOT", &source_root) + // Provide path to stage-corresponding rustc. + .env("RUSTC", &self.config.rustc_path) + // Provide the directory to libraries that are needed to run the *compiler*. This is not + // to be confused with `TARGET_RPATH_ENV` or `TARGET_RPATH_DIR`. This is needed if the + // recipe wants to invoke rustc. + .env("HOST_RPATH_DIR", &self.config.compile_lib_path) + // Provide the directory to libraries that might be needed to run compiled binaries + // (further compiled by the recipe!). + .env("TARGET_RPATH_DIR", &self.config.run_lib_path) + // Provide which LLVM components are available (e.g. which LLVM components are provided + // through a specific CI runner). .env("LLVM_COMPONENTS", &self.config.llvm_components); if let Some(ref rustdoc) = self.config.rustdoc_path { - cmd.env("RUSTDOC", cwd.join(rustdoc)); + cmd.env("RUSTDOC", source_root.join(rustdoc)); } if let Some(ref node) = self.config.nodejs { diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff index 1aeaaff21dceb..3b739a25cb864 100644 --- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.foo.DataflowConstProp.diff @@ -57,9 +57,7 @@ StorageDead(_1); return; } -+ } -+ -+ ALLOC0 (size: 8, align: 4) { -+ 05 00 00 00 03 00 00 00 │ ........ } ++ ++ ALLOC0 (size: 8, align: 4) { .. } diff --git a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs index aca5f047222f5..9cd485813bc99 100644 --- a/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs +++ b/tests/mir-opt/dataflow-const-prop/aggregate_copy.rs @@ -1,6 +1,7 @@ //! Verify that we manage to propagate the value of aggregate `a` even without directly mentioning //! the contained scalars. //@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zdump-mir-exclude-alloc-bytes const Foo: (u32, u32) = (5, 3); diff --git a/tests/rustdoc-gui/src/test_docs/lib.rs b/tests/rustdoc-gui/src/test_docs/lib.rs index 7e34178e56f03..6c638dc3b9d87 100644 --- a/tests/rustdoc-gui/src/test_docs/lib.rs +++ b/tests/rustdoc-gui/src/test_docs/lib.rs @@ -614,3 +614,9 @@ pub mod private { B, } } + +pub mod trait_bounds { + pub trait OneBound: Sized {} + pub trait TwoBounds: Sized + Copy {} + pub trait ThreeBounds: Sized + Copy + Eq {} +} diff --git a/tests/rustdoc-gui/trait-with-bounds.goml b/tests/rustdoc-gui/trait-with-bounds.goml new file mode 100644 index 0000000000000..f076bdd47070d --- /dev/null +++ b/tests/rustdoc-gui/trait-with-bounds.goml @@ -0,0 +1,35 @@ +// Check that if a trait has more than 2 bounds, they are displayed on different lines. + +// It tries to load a JS for each trait but there are none since they're not implemented. +fail-on-request-error: false +go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/trait.OneBound.html" +// They should have the same Y position. +compare-elements-position: ( + ".item-decl code", + ".item-decl a.trait[title='trait core::marker::Sized']", + ["y"], +) +go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/trait.TwoBounds.html" +// They should have the same Y position. +compare-elements-position: ( + ".item-decl code", + ".item-decl a.trait[title='trait core::marker::Copy']", + ["y"], +) +go-to: "file://" + |DOC_PATH| + "/test_docs/trait_bounds/trait.ThreeBounds.html" +// All on their own line. +compare-elements-position-false: ( + ".item-decl code", + ".item-decl a.trait[title='trait core::marker::Sized']", + ["y"], +) +compare-elements-position-false: ( + ".item-decl a.trait[title='trait core::marker::Sized']", + ".item-decl a.trait[title='trait core::marker::Copy']", + ["y"], +) +compare-elements-position-false: ( + ".item-decl a.trait[title='trait core::marker::Copy']", + ".item-decl a.trait[title='trait core::cmp::Eq']", + ["y"], +) diff --git a/tests/rustdoc-gui/type-declation-overflow.goml b/tests/rustdoc-gui/type-declation-overflow.goml index fdf84c3fd2950..8df946c6f39ed 100644 --- a/tests/rustdoc-gui/type-declation-overflow.goml +++ b/tests/rustdoc-gui/type-declation-overflow.goml @@ -8,34 +8,38 @@ fail-on-request-error: false go-to: "file://" + |DOC_PATH| + "/lib2/long_trait/trait.ALongNameBecauseItHelpsTestingTheCurrentProblem.html" // We set a fixed size so there is no chance of "random" resize. -set-window-size: (1100, 800) +set-window-size: (710, 800) // Logically, the scroll width should be the width of the window. -assert-property: ("body", {"scrollWidth": "1100"}) -// However, since there is overflow in the type declaration, its scroll width is bigger. -assert-property: ("pre.item-decl", {"scrollWidth": "1324"}) +assert-property: ("body", {"scrollWidth": "710"}) +// We now check that the section width hasn't grown because of it. +assert-property: ("#main-content", {"scrollWidth": "450"}) +// However, since there is overflow in the type declaration, its scroll width is bigger that "#main-content". +assert-property: ("pre.item-decl", {"scrollWidth": "585"}) // In the table-ish view on the module index, the name should not be wrapped more than necessary. go-to: "file://" + |DOC_PATH| + "/lib2/too_long/index.html" // We'll ensure that items with short documentation have the same width. store-property: ("//*[@class='item-table']//*[@class='struct']/..", {"offsetWidth": offset_width}) -assert: |offset_width| == "277" +assert: |offset_width| == "149" assert-property: ("//*[@class='item-table']//*[@class='constant']/..", {"offsetWidth": |offset_width|}) // We now make the same check on type declaration... go-to: "file://" + |DOC_PATH| + "/lib2/too_long/type.ReallyLongTypeNameLongLongLong.html" -assert-property: ("body", {"scrollWidth": "1100"}) +assert-property: ("body", {"scrollWidth": "710"}) +// Getting the width of the "
" element. +assert-property: ("main", {"scrollWidth": "510"}) // We now check that the section width hasn't grown because of it. -assert-property: ("#main-content", {"scrollWidth": "840"}) +assert-property: ("#main-content", {"scrollWidth": "450"}) // And now checking that it has scrollable content. assert-property: ("pre.item-decl", {"scrollWidth": "1103"}) // ... and constant. // On a sidenote, it also checks that the (very) long title isn't changing the docblock width. go-to: "file://" + |DOC_PATH| + "/lib2/too_long/constant.ReallyLongTypeNameLongLongLongConstBecauseWhyNotAConstRightGigaGigaSupraLong.html" -assert-property: ("body", {"scrollWidth": "1100"}) +assert-property: ("body", {"scrollWidth": "710"}) // We now check that the section width hasn't grown because of it. -assert-property: ("#main-content", {"scrollWidth": "840"}) +assert-property: ("#main-content", {"scrollWidth": "450"}) // And now checking that it has scrollable content. assert-property: ("pre.item-decl", {"scrollWidth": "950"}) diff --git a/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs b/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs new file mode 100644 index 0000000000000..781443207ac19 --- /dev/null +++ b/tests/ui/macros/macro-metavar-expr-concat/repetitions.rs @@ -0,0 +1,18 @@ +//@ run-pass + +#![feature(macro_metavar_expr_concat)] + +macro_rules! one_rep { + ( $($a:ident)* ) => { + $( + const ${concat($a, Z)}: i32 = 3; + )* + }; +} + +fn main() { + one_rep!(A B C); + assert_eq!(AZ, 3); + assert_eq!(BZ, 3); + assert_eq!(CZ, 3); +}