1
Fork 0

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:
bors 2024-07-21 00:39:36 +00:00
commit 2430c48b57
19 changed files with 455 additions and 277 deletions

View file

@ -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);

View file

@ -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,
}
}
}

View file

@ -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))
}

View file

@ -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(

View file

@ -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

View file

@ -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],

View file

@ -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)))
}

View file

@ -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 {

View file

@ -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

View file

@ -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
}

View file

@ -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",

View file

@ -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

View file

@ -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 {

View file

@ -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) { .. }

View file

@ -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);

View file

@ -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 {}
}

View 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"],
)

View file

@ -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"})

View 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);
}