Auto merge of #128011 - matthiaskrgr:rollup-0vmf75y, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #127720 ([`macro_metavar_expr_concat`] Allow `concat` in repetitions) - #127734 (Windows: move BSD socket shims to netc) - #127752 (Ignore allocation bytes in one more mir-opt test) - #127839 (Fix git safe-directory path for docker images) - #127867 (Add `wasm32-wasip2` to `build-manifest` tool) - #127958 (Cleanup rmake.rs setup in compiletest) - #127975 (Fix trait bounds display) - #128005 (Remove _tls_used hack) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
2430c48b57
19 changed files with 455 additions and 277 deletions
|
@ -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);
|
||||
|
|
|
@ -111,10 +111,18 @@ impl MetaVarExpr {
|
|||
Ok(rslt)
|
||||
}
|
||||
|
||||
pub(crate) fn ident(&self) -> Option<Ident> {
|
||||
match *self {
|
||||
MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
|
||||
MetaVarExpr::Concat { .. } | MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None,
|
||||
pub(crate) fn for_each_metavar<A>(&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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<MacroRulesNormalizedIdent, NamedMatch>,
|
||||
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))
|
||||
}
|
||||
|
|
|
@ -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::<u8>(), 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::<u8>(), 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::<u8>(), 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::<u8>(), 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::<u8>(), service.cast::<u8>(), hints, res)
|
||||
}
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(target_vendor = "uwp"))] {
|
||||
pub unsafe fn NtReadFile(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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::<u8>(), 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::<u8>(), 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::<u8>(), service.cast::<u8>(), hints, res) }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Socket(OwnedSocket);
|
||||
|
@ -102,8 +188,8 @@ where
|
|||
impl Socket {
|
||||
pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
|
||||
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::<c::fd_set>() };
|
||||
let mut fds = unsafe { mem::zeroed::<c::FD_SET>() };
|
||||
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::<c::SOCKADDR_STORAGE_LH>() };
|
||||
let mut addrlen = mem::size_of_val(&storage) as c::socklen_t;
|
||||
let mut storage = unsafe { mem::zeroed::<c::SOCKADDR_STORAGE>() };
|
||||
let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
|
||||
let length = cmp::min(buf.len(), <wrlen_t>::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<Duration>) -> 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<Option<Duration>> {
|
||||
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)))
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/<host_triple>/test/run-make`. But we want `build/<host_triple>/`. 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/
|
||||
// <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-<target_triple>`, 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/<target_triple>/ // <- 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/<target_triple>/
|
||||
// ├── stageN-tools-bin/
|
||||
// │ └── librun_make_support.rlib // <- support rlib itself
|
||||
// ├── stageN-tools/
|
||||
// │ ├── release/deps/ // <- deps of deps
|
||||
// │ └── <host_triple>/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 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");
|
||||
|
||||
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");
|
||||
// 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 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 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
|
||||
};
|
||||
|
||||
let mut cmd = Command::new(&self.config.rustc_path);
|
||||
cmd.arg("-o")
|
||||
// Calculate the paths of the recipe binary. As previously discussed, this is placed at
|
||||
// `<base_dir>/<bin_name>` 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 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 <https://github.com/rust-lang/rust/pull/122248> 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.
|
||||
|
||||
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 stage-specific standard library paths.
|
||||
let stage_std_path = build_root.join(&stage).join("lib");
|
||||
|
||||
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 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
|
||||
};
|
||||
|
||||
// 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 {
|
||||
|
|
|
@ -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) { .. }
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 {}
|
||||
}
|
||||
|
|
35
tests/rustdoc-gui/trait-with-bounds.goml
Normal file
35
tests/rustdoc-gui/trait-with-bounds.goml
Normal file
|
@ -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"],
|
||||
)
|
|
@ -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 <body> 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 "<main>" 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"})
|
||||
|
||||
|
|
18
tests/ui/macros/macro-metavar-expr-concat/repetitions.rs
Normal file
18
tests/ui/macros/macro-metavar-expr-concat/repetitions.rs
Normal file
|
@ -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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue