Auto merge of #120341 - matthiaskrgr:rollup-lvm59cj, r=matthiaskrgr

Rollup of 8 pull requests

Successful merges:

 - #118208 (Rewrite the BTreeMap cursor API using gaps)
 - #120099 (linker: Refactor library linking methods in `trait Linker`)
 - #120288 (Bump `askama` version)
 - #120306 (Clean up after clone3 removal from pidfd code (docs and tests))
 - #120316 (Don't call `walk_` functions directly if there is an equivalent `visit_` method)
 - #120330 (Remove coroutine info when building coroutine drop body)
 - #120332 (Remove unused struct)
 - #120338 (Fix links to [strict|exposed] provenance sections of `[std|core]::ptr`)

r? `@ghost`
`@rustbot` modify labels: rollup
This commit is contained in:
bors 2024-01-25 21:59:29 +00:00
commit 0c1fb2a1e6
21 changed files with 916 additions and 847 deletions

View file

@ -212,9 +212,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]]
name = "askama"
version = "0.12.0"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47cbc3cf73fa8d9833727bbee4835ba5c421a0d65b72daf9a7b5d0e0f9cfb57e"
checksum = "b79091df18a97caea757e28cd2d5fda49c6cd4bd01ddffd7ff01ace0c0ad2c28"
dependencies = [
"askama_derive",
"askama_escape",
@ -222,14 +222,14 @@ dependencies = [
[[package]]
name = "askama_derive"
version = "0.12.1"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c22fbe0413545c098358e56966ff22cdd039e10215ae213cfbd65032b119fc94"
checksum = "19fe8d6cb13c4714962c072ea496f3392015f0989b1a2847bb4b2d9effd71d83"
dependencies = [
"askama_parser",
"basic-toml",
"mime",
"mime_guess",
"nom",
"proc-macro2",
"quote",
"serde",
@ -242,6 +242,15 @@ version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341"
[[package]]
name = "askama_parser"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acb1161c6b64d1c3d83108213c2a2533a342ac225aabd0bda218278c2ddb00c0"
dependencies = [
"nom",
]
[[package]]
name = "autocfg"
version = "1.1.0"

View file

@ -375,11 +375,11 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) {
}
ItemKind::MacCall(mac) => visitor.visit_mac_call(mac),
ItemKind::MacroDef(ts) => visitor.visit_mac_def(ts, item.id),
ItemKind::Delegation(box Delegation { id: _, qself, path, body }) => {
ItemKind::Delegation(box Delegation { id, qself, path, body }) => {
if let Some(qself) = qself {
visitor.visit_ty(&qself.ty);
}
walk_path(visitor, path);
visitor.visit_path(path, *id);
if let Some(body) = body {
visitor.visit_block(body);
}
@ -502,7 +502,7 @@ where
}
GenericArgs::Parenthesized(data) => {
walk_list!(visitor, visit_ty, &data.inputs);
walk_fn_ret_ty(visitor, &data.output);
visitor.visit_fn_ret_ty(&data.output);
}
}
}
@ -713,11 +713,11 @@ pub fn walk_assoc_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a AssocItem,
AssocItemKind::MacCall(mac) => {
visitor.visit_mac_call(mac);
}
AssocItemKind::Delegation(box Delegation { id: _, qself, path, body }) => {
AssocItemKind::Delegation(box Delegation { id, qself, path, body }) => {
if let Some(qself) = qself {
visitor.visit_ty(&qself.ty);
}
walk_path(visitor, path);
visitor.visit_path(path, *id);
if let Some(body) = body {
visitor.visit_block(body);
}

View file

@ -52,6 +52,15 @@ use std::path::{Path, PathBuf};
use std::process::{ExitStatus, Output, Stdio};
use std::{env, fmt, fs, io, mem, str};
#[derive(Default)]
pub struct SearchPaths(OnceCell<Vec<PathBuf>>);
impl SearchPaths {
pub(super) fn get(&self, sess: &Session) -> &[PathBuf] {
self.0.get_or_init(|| archive_search_paths(sess))
}
}
pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) {
if let Err(e) = fs::remove_file(path) {
if e.kind() != io::ErrorKind::NotFound {
@ -1265,7 +1274,7 @@ fn link_sanitizer_runtime(
let path = find_sanitizer_runtime(sess, &filename);
let rpath = path.to_str().expect("non-utf8 component in path");
linker.args(&["-Wl,-rpath", "-Xlinker", rpath]);
linker.link_dylib(&filename, false, true);
linker.link_dylib_by_name(&filename, false, true);
} else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" {
// MSVC provides the `/INFERASANLIBS` argument to automatically find the
// compatible ASAN library.
@ -1273,7 +1282,7 @@ fn link_sanitizer_runtime(
} else {
let filename = format!("librustc{channel}_rt.{name}.a");
let path = find_sanitizer_runtime(sess, &filename).join(&filename);
linker.link_whole_rlib(&path);
linker.link_staticlib_by_path(&path, true);
}
}
@ -2445,7 +2454,7 @@ fn add_native_libs_from_crate(
archive_builder_builder: &dyn ArchiveBuilderBuilder,
codegen_results: &CodegenResults,
tmpdir: &Path,
search_paths: &OnceCell<Vec<PathBuf>>,
search_paths: &SearchPaths,
bundled_libs: &FxHashSet<Symbol>,
cnum: CrateNum,
link_static: bool,
@ -2505,28 +2514,16 @@ fn add_native_libs_from_crate(
if let Some(filename) = lib.filename {
// If rlib contains native libs as archives, they are unpacked to tmpdir.
let path = tmpdir.join(filename.as_str());
if whole_archive {
cmd.link_whole_rlib(&path);
} else {
cmd.link_rlib(&path);
}
cmd.link_staticlib_by_path(&path, whole_archive);
}
} else {
if whole_archive {
cmd.link_whole_staticlib(
name,
verbatim,
search_paths.get_or_init(|| archive_search_paths(sess)),
);
} else {
cmd.link_staticlib(name, verbatim)
}
cmd.link_staticlib_by_name(name, verbatim, whole_archive, search_paths);
}
}
}
NativeLibKind::Dylib { as_needed } => {
if link_dynamic {
cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true))
cmd.link_dylib_by_name(name, verbatim, as_needed.unwrap_or(true))
}
}
NativeLibKind::Unspecified => {
@ -2534,17 +2531,17 @@ fn add_native_libs_from_crate(
// link kind is unspecified.
if !link_output_kind.can_link_dylib() && !sess.target.crt_static_allows_dylibs {
if link_static {
cmd.link_staticlib(name, verbatim)
cmd.link_staticlib_by_name(name, verbatim, false, search_paths);
}
} else {
if link_dynamic {
cmd.link_dylib(name, verbatim, true);
cmd.link_dylib_by_name(name, verbatim, true);
}
}
}
NativeLibKind::Framework { as_needed } => {
if link_dynamic {
cmd.link_framework(name, as_needed.unwrap_or(true))
cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true))
}
}
NativeLibKind::RawDylib => {
@ -2581,7 +2578,7 @@ fn add_local_native_libraries(
}
}
let search_paths = OnceCell::new();
let search_paths = SearchPaths::default();
// All static and dynamic native library dependencies are linked to the local crate.
let link_static = true;
let link_dynamic = true;
@ -2623,7 +2620,7 @@ fn add_upstream_rust_crates<'a>(
.find(|(ty, _)| *ty == crate_type)
.expect("failed to find crate type in dependency format list");
let search_paths = OnceCell::new();
let search_paths = SearchPaths::default();
for &cnum in &codegen_results.crate_info.used_crates {
// We may not pass all crates through to the linker. Some crates may appear statically in
// an existing dylib, meaning we'll pick up all the symbols from the dylib.
@ -2698,7 +2695,7 @@ fn add_upstream_native_libraries(
tmpdir: &Path,
link_output_kind: LinkOutputKind,
) {
let search_path = OnceCell::new();
let search_paths = SearchPaths::default();
for &cnum in &codegen_results.crate_info.used_crates {
// Static libraries are not linked here, they are linked in `add_upstream_rust_crates`.
// FIXME: Merge this function to `add_upstream_rust_crates` so that all native libraries
@ -2720,7 +2717,7 @@ fn add_upstream_native_libraries(
archive_builder_builder,
codegen_results,
tmpdir,
&search_path,
&search_paths,
&Default::default(),
cnum,
link_static,
@ -2791,7 +2788,7 @@ fn add_static_crate<'a>(
} else {
fix_windows_verbatim_for_gcc(path)
};
cmd.link_rlib(&rlib_path);
cmd.link_staticlib_by_path(&rlib_path, false);
};
if !are_upstream_rust_objects_already_included(sess)
@ -2859,13 +2856,24 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) {
// Just need to tell the linker about where the library lives and
// what its name is
let parent = cratepath.parent();
// When producing a dll, the MSVC linker may not actually emit a
// `foo.lib` file if the dll doesn't actually export any symbols, so we
// check to see if the file is there and just omit linking to it if it's
// not present.
if sess.target.is_like_msvc && !cratepath.with_extension("dll.lib").exists() {
return;
}
if let Some(dir) = parent {
cmd.include_path(&rehome_sysroot_lib_dir(sess, dir));
}
let stem = cratepath.file_stem().unwrap().to_str().unwrap();
// "<dir>/name.dll -> name.dll" on windows-msvc
// "<dir>/name.dll -> name" on windows-gnu
// "<dir>/libname.<ext> -> name" elsewhere
let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() };
let stem = stem.unwrap().to_str().unwrap();
// Convert library file-stem into a cc -l argument.
let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 };
cmd.link_rust_dylib(&stem[prefix..], parent.unwrap_or_else(|| Path::new("")));
cmd.link_dylib_by_name(&stem[prefix..], false, true);
}
fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool {

View file

@ -1,5 +1,6 @@
use super::command::Command;
use super::symbol_export;
use crate::back::link::SearchPaths;
use crate::errors;
use rustc_span::symbol::sym;
@ -166,13 +167,18 @@ pub fn get_linker<'a>(
pub trait Linker {
fn cmd(&mut self) -> &mut Command;
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool);
fn link_rust_dylib(&mut self, lib: &str, path: &Path);
fn link_framework(&mut self, framework: &str, as_needed: bool);
fn link_staticlib(&mut self, lib: &str, verbatim: bool);
fn link_rlib(&mut self, lib: &Path);
fn link_whole_rlib(&mut self, lib: &Path);
fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]);
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool);
fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
bug!("framework linked with unsupported linker")
}
fn link_staticlib_by_name(
&mut self,
name: &str,
verbatim: bool,
whole_archive: bool,
search_paths: &SearchPaths,
);
fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool);
fn include_path(&mut self, path: &Path);
fn framework_path(&mut self, path: &Path);
fn output_filename(&mut self, path: &Path);
@ -432,8 +438,8 @@ impl<'a> Linker for GccLinker<'a> {
}
}
fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool) {
if self.sess.target.os == "illumos" && lib == "c" {
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) {
if self.sess.target.os == "illumos" && name == "c" {
// libc will be added via late_link_args on illumos so that it will
// appear last in the library search order.
// FIXME: This should be replaced by a more complete and generic
@ -454,7 +460,7 @@ impl<'a> Linker for GccLinker<'a> {
}
}
self.hint_dynamic();
self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },));
if !as_needed {
if self.sess.target.is_like_osx {
// See above FIXME comment
@ -463,14 +469,56 @@ impl<'a> Linker for GccLinker<'a> {
}
}
}
fn link_staticlib(&mut self, lib: &str, verbatim: bool) {
self.hint_static();
self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) {
self.hint_dynamic();
if !as_needed {
// FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
// flag but we have no way to detect that here.
// self.cmd.arg("-needed_framework").arg(name);
self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
}
self.cmd.arg("-framework").arg(name);
}
fn link_rlib(&mut self, lib: &Path) {
fn link_staticlib_by_name(
&mut self,
name: &str,
verbatim: bool,
whole_archive: bool,
search_paths: &SearchPaths,
) {
self.hint_static();
self.cmd.arg(lib);
let colon = if verbatim && self.is_gnu { ":" } else { "" };
if !whole_archive {
self.cmd.arg(format!("-l{colon}{name}"));
} else if self.sess.target.is_like_osx {
// -force_load is the macOS equivalent of --whole-archive, but it
// involves passing the full path to the library to link.
self.linker_arg("-force_load");
let search_paths = search_paths.get(self.sess);
self.linker_arg(find_native_static_library(name, verbatim, search_paths, self.sess));
} else {
self.linker_arg("--whole-archive");
self.cmd.arg(format!("-l{colon}{name}"));
self.linker_arg("--no-whole-archive");
}
}
fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
self.hint_static();
if !whole_archive {
self.cmd.arg(path);
} else if self.sess.target.is_like_osx {
self.linker_arg("-force_load");
self.linker_arg(path);
} else {
self.linker_arg("--whole-archive");
self.linker_arg(path);
self.linker_arg("--no-whole-archive");
}
}
fn include_path(&mut self, path: &Path) {
self.cmd.arg("-L").arg(path);
}
@ -493,55 +541,6 @@ impl<'a> Linker for GccLinker<'a> {
self.linker_args(&["-z", "norelro"]);
}
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
self.hint_dynamic();
self.cmd.arg(format!("-l{lib}"));
}
fn link_framework(&mut self, framework: &str, as_needed: bool) {
self.hint_dynamic();
if !as_needed {
// FIXME(81490): ld64 as of macOS 11 supports the -needed_framework
// flag but we have no way to detect that here.
// self.cmd.arg("-needed_framework").arg(framework);
self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier);
}
self.cmd.arg("-framework").arg(framework);
}
// Here we explicitly ask that the entire archive is included into the
// result artifact. For more details see #15460, but the gist is that
// the linker will strip away any unused objects in the archive if we
// don't otherwise explicitly reference them. This can occur for
// libraries which are just providing bindings, libraries with generic
// functions, etc.
fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) {
self.hint_static();
let target = &self.sess.target;
if !target.is_like_osx {
self.linker_arg("--whole-archive");
self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },));
self.linker_arg("--no-whole-archive");
} else {
// -force_load is the macOS equivalent of --whole-archive, but it
// involves passing the full path to the library to link.
self.linker_arg("-force_load");
let lib = find_native_static_library(lib, verbatim, search_path, self.sess);
self.linker_arg(&lib);
}
}
fn link_whole_rlib(&mut self, lib: &Path) {
self.hint_static();
if self.sess.target.is_like_osx {
self.linker_arg("-force_load");
self.linker_arg(&lib);
} else {
self.linker_args(&[OsString::from("--whole-archive"), lib.into()]);
self.linker_arg("--no-whole-archive");
}
}
fn gc_sections(&mut self, keep_metadata: bool) {
// The dead_strip option to the linker specifies that functions and data
// unreachable by the entry point will be removed. This is quite useful
@ -821,9 +820,32 @@ impl<'a> Linker for MsvcLinker<'a> {
}
}
fn link_rlib(&mut self, lib: &Path) {
self.cmd.arg(lib);
fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) {
self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" }));
}
fn link_staticlib_by_name(
&mut self,
name: &str,
verbatim: bool,
whole_archive: bool,
_search_paths: &SearchPaths,
) {
let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" };
let suffix = if verbatim { "" } else { ".lib" };
self.cmd.arg(format!("{prefix}{name}{suffix}"));
}
fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
if !whole_archive {
self.cmd.arg(path);
} else {
let mut arg = OsString::from("/WHOLEARCHIVE:");
arg.push(path);
self.cmd.arg(arg);
}
}
fn add_object(&mut self, path: &Path) {
self.cmd.arg(path);
}
@ -845,25 +867,6 @@ impl<'a> Linker for MsvcLinker<'a> {
self.cmd.arg("/OPT:NOREF,NOICF");
}
fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) {
self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
}
fn link_rust_dylib(&mut self, lib: &str, path: &Path) {
// When producing a dll, the MSVC linker may not actually emit a
// `foo.lib` file if the dll doesn't actually export any symbols, so we
// check to see if the file is there and just omit linking to it if it's
// not present.
let name = format!("{lib}.dll.lib");
if path.join(&name).exists() {
self.cmd.arg(name);
}
}
fn link_staticlib(&mut self, lib: &str, verbatim: bool) {
self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" }));
}
fn full_relro(&mut self) {
// noop
}
@ -899,18 +902,7 @@ impl<'a> Linker for MsvcLinker<'a> {
fn framework_path(&mut self, _path: &Path) {
bug!("frameworks are not supported on windows")
}
fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
bug!("frameworks are not supported on windows")
}
fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) {
self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" }));
}
fn link_whole_rlib(&mut self, path: &Path) {
let mut arg = OsString::from("/WHOLEARCHIVE:");
arg.push(path);
self.cmd.arg(arg);
}
fn optimize(&mut self) {
// Needs more investigation of `/OPT` arguments
}
@ -1057,12 +1049,27 @@ impl<'a> Linker for EmLinker<'a> {
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn include_path(&mut self, path: &Path) {
self.cmd.arg("-L").arg(path);
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
// Emscripten always links statically
self.cmd.arg("-l").arg(name);
}
fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
self.cmd.arg("-l").arg(lib);
fn link_staticlib_by_name(
&mut self,
name: &str,
_verbatim: bool,
_whole_archive: bool,
_search_paths: &SearchPaths,
) {
self.cmd.arg("-l").arg(name);
}
fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
self.cmd.arg(path);
}
fn include_path(&mut self, path: &Path) {
self.cmd.arg("-L").arg(path);
}
fn output_filename(&mut self, path: &Path) {
@ -1073,29 +1080,6 @@ impl<'a> Linker for EmLinker<'a> {
self.cmd.arg(path);
}
fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) {
// Emscripten always links statically
self.link_staticlib(lib, verbatim);
}
fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) {
// not supported?
self.link_staticlib(lib, verbatim);
}
fn link_whole_rlib(&mut self, lib: &Path) {
// not supported?
self.link_rlib(lib);
}
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
self.link_dylib(lib, false, true);
}
fn link_rlib(&mut self, lib: &Path) {
self.add_object(lib);
}
fn full_relro(&mut self) {
// noop
}
@ -1112,10 +1096,6 @@ impl<'a> Linker for EmLinker<'a> {
bug!("frameworks are not supported on Emscripten")
}
fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
bug!("frameworks are not supported on Emscripten")
}
fn gc_sections(&mut self, _keep_metadata: bool) {
// noop
}
@ -1249,16 +1229,30 @@ impl<'a> Linker for WasmLd<'a> {
}
}
fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) {
self.cmd.arg("-l").arg(lib);
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
self.cmd.arg("-l").arg(name);
}
fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
self.cmd.arg("-l").arg(lib);
fn link_staticlib_by_name(
&mut self,
name: &str,
_verbatim: bool,
whole_archive: bool,
_search_paths: &SearchPaths,
) {
if !whole_archive {
self.cmd.arg("-l").arg(name);
} else {
self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive");
}
}
fn link_rlib(&mut self, lib: &Path) {
self.cmd.arg(lib);
fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
if !whole_archive {
self.cmd.arg(path);
} else {
self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive");
}
}
fn include_path(&mut self, path: &Path) {
@ -1283,22 +1277,6 @@ impl<'a> Linker for WasmLd<'a> {
fn no_relro(&mut self) {}
fn link_rust_dylib(&mut self, lib: &str, _path: &Path) {
self.cmd.arg("-l").arg(lib);
}
fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
panic!("frameworks not supported")
}
fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
self.cmd.arg("--whole-archive").arg("-l").arg(lib).arg("--no-whole-archive");
}
fn link_whole_rlib(&mut self, lib: &Path) {
self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive");
}
fn gc_sections(&mut self, _keep_metadata: bool) {
self.cmd.arg("--gc-sections");
}
@ -1398,17 +1376,40 @@ pub struct L4Bender<'a> {
}
impl<'a> Linker for L4Bender<'a> {
fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) {
fn cmd(&mut self) -> &mut Command {
&mut self.cmd
}
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
bug!("dylibs are not supported on L4Re");
}
fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
fn link_staticlib_by_name(
&mut self,
name: &str,
_verbatim: bool,
whole_archive: bool,
_search_paths: &SearchPaths,
) {
self.hint_static();
self.cmd.arg(format!("-PC{lib}"));
if !whole_archive {
self.cmd.arg(format!("-PC{name}"));
} else {
self.cmd.arg("--whole-archive").arg(format!("-l{name}")).arg("--no-whole-archive");
}
}
fn link_rlib(&mut self, lib: &Path) {
fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
self.hint_static();
self.cmd.arg(lib);
if !whole_archive {
self.cmd.arg(path);
} else {
self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive");
}
}
fn include_path(&mut self, path: &Path) {
self.cmd.arg("-L").arg(path);
}
@ -1436,31 +1437,6 @@ impl<'a> Linker for L4Bender<'a> {
self.cmd.arg("-z").arg("norelro");
}
fn cmd(&mut self) -> &mut Command {
&mut self.cmd
}
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn link_rust_dylib(&mut self, _: &str, _: &Path) {
panic!("Rust dylibs not supported");
}
fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
bug!("frameworks not supported on L4Re");
}
fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
self.hint_static();
self.cmd.arg("--whole-archive").arg(format!("-l{lib}"));
self.cmd.arg("--no-whole-archive");
}
fn link_whole_rlib(&mut self, lib: &Path) {
self.hint_static();
self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive");
}
fn gc_sections(&mut self, keep_metadata: bool) {
if !keep_metadata {
self.cmd.arg("--gc-sections");
@ -1571,19 +1547,56 @@ impl<'a> AixLinker<'a> {
}
impl<'a> Linker for AixLinker<'a> {
fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) {
fn cmd(&mut self) -> &mut Command {
&mut self.cmd
}
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
match output_kind {
LinkOutputKind::DynamicDylib => {
self.hint_dynamic();
self.build_dylib(out_filename);
}
LinkOutputKind::StaticDylib => {
self.hint_static();
self.build_dylib(out_filename);
}
_ => {}
}
}
fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) {
self.hint_dynamic();
self.cmd.arg(format!("-l{lib}"));
self.cmd.arg(format!("-l{name}"));
}
fn link_staticlib(&mut self, lib: &str, _verbatim: bool) {
fn link_staticlib_by_name(
&mut self,
name: &str,
verbatim: bool,
whole_archive: bool,
search_paths: &SearchPaths,
) {
self.hint_static();
self.cmd.arg(format!("-l{lib}"));
if !whole_archive {
self.cmd.arg(format!("-l{name}"));
} else {
let mut arg = OsString::from("-bkeepfile:");
let search_path = search_paths.get(self.sess);
arg.push(find_native_static_library(name, verbatim, search_path, self.sess));
self.cmd.arg(arg);
}
}
fn link_rlib(&mut self, lib: &Path) {
fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) {
self.hint_static();
self.cmd.arg(lib);
if !whole_archive {
self.cmd.arg(path);
} else {
let mut arg = OsString::from("-bkeepfile:");
arg.push(path);
self.cmd.arg(arg);
}
}
fn include_path(&mut self, path: &Path) {
@ -1608,44 +1621,6 @@ impl<'a> Linker for AixLinker<'a> {
fn no_relro(&mut self) {}
fn cmd(&mut self) -> &mut Command {
&mut self.cmd
}
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
match output_kind {
LinkOutputKind::DynamicDylib => {
self.hint_dynamic();
self.build_dylib(out_filename);
}
LinkOutputKind::StaticDylib => {
self.hint_static();
self.build_dylib(out_filename);
}
_ => {}
}
}
fn link_rust_dylib(&mut self, lib: &str, _: &Path) {
self.hint_dynamic();
self.cmd.arg(format!("-l{lib}"));
}
fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
bug!("frameworks not supported on AIX");
}
fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) {
self.hint_static();
let lib = find_native_static_library(lib, verbatim, search_path, self.sess);
self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap()));
}
fn link_whole_rlib(&mut self, lib: &Path) {
self.hint_static();
self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap()));
}
fn gc_sections(&mut self, _keep_metadata: bool) {
self.cmd.arg("-bgc");
}
@ -1810,11 +1785,21 @@ impl<'a> Linker for PtxLinker<'a> {
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn link_rlib(&mut self, path: &Path) {
self.cmd.arg("--rlib").arg(path);
fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
panic!("external dylibs not supported")
}
fn link_whole_rlib(&mut self, path: &Path) {
fn link_staticlib_by_name(
&mut self,
_name: &str,
_verbatim: bool,
_whole_archive: bool,
_search_paths: &SearchPaths,
) {
panic!("staticlibs not supported")
}
fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
self.cmd.arg("--rlib").arg(path);
}
@ -1844,30 +1829,10 @@ impl<'a> Linker for PtxLinker<'a> {
self.cmd.arg("-o").arg(path);
}
fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) {
panic!("external dylibs not supported")
}
fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
panic!("external dylibs not supported")
}
fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) {
panic!("staticlibs not supported")
}
fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
panic!("staticlibs not supported")
}
fn framework_path(&mut self, _path: &Path) {
panic!("frameworks not supported")
}
fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
panic!("frameworks not supported")
}
fn full_relro(&mut self) {}
fn partial_relro(&mut self) {}
@ -1907,11 +1872,21 @@ impl<'a> Linker for BpfLinker<'a> {
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
fn link_rlib(&mut self, path: &Path) {
self.cmd.arg(path);
fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) {
panic!("external dylibs not supported")
}
fn link_whole_rlib(&mut self, path: &Path) {
fn link_staticlib_by_name(
&mut self,
_name: &str,
_verbatim: bool,
_whole_archive: bool,
_search_paths: &SearchPaths,
) {
panic!("staticlibs not supported")
}
fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) {
self.cmd.arg(path);
}
@ -1942,30 +1917,10 @@ impl<'a> Linker for BpfLinker<'a> {
self.cmd.arg("-o").arg(path);
}
fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) {
panic!("external dylibs not supported")
}
fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) {
panic!("external dylibs not supported")
}
fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) {
panic!("staticlibs not supported")
}
fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) {
panic!("staticlibs not supported")
}
fn framework_path(&mut self, _path: &Path) {
panic!("frameworks not supported")
}
fn link_framework(&mut self, _framework: &str, _as_needed: bool) {
panic!("frameworks not supported")
}
fn full_relro(&mut self) {}
fn partial_relro(&mut self) {}

View file

@ -244,18 +244,23 @@ impl<'tcx> MirSource<'tcx> {
}
}
/// Additional information carried by a MIR body when it is lowered from a coroutine.
/// This information is modified as it is lowered during the `StateTransform` MIR pass,
/// so not all fields will be active at a given time. For example, the `yield_ty` is
/// taken out of the field after yields are turned into returns, and the `coroutine_drop`
/// body is only populated after the state transform pass.
#[derive(Clone, TyEncodable, TyDecodable, Debug, HashStable, TypeFoldable, TypeVisitable)]
pub struct CoroutineInfo<'tcx> {
/// The yield type of the function, if it is a coroutine.
/// The yield type of the function. This field is removed after the state transform pass.
pub yield_ty: Option<Ty<'tcx>>,
/// The resume type of the function, if it is a coroutine.
/// The resume type of the function. This field is removed after the state transform pass.
pub resume_ty: Option<Ty<'tcx>>,
/// Coroutine drop glue.
/// Coroutine drop glue. This field is populated after the state transform pass.
pub coroutine_drop: Option<Body<'tcx>>,
/// The layout of a coroutine. Produced by the state transformation.
/// The layout of a coroutine. This field is populated after the state transform pass.
pub coroutine_layout: Option<CoroutineLayout<'tcx>>,
/// If this is a coroutine then record the type of source expression that caused this coroutine
@ -303,6 +308,12 @@ pub struct Body<'tcx> {
/// and used for debuginfo. Indexed by a `SourceScope`.
pub source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
/// Additional information carried by a MIR body when it is lowered from a coroutine.
///
/// Note that the coroutine drop shim, any promoted consts, and other synthetic MIR
/// bodies that come from processing a coroutine body are not typically coroutines
/// themselves, and should probably set this to `None` to avoid carrying redundant
/// information.
pub coroutine: Option<Box<CoroutineInfo<'tcx>>>,
/// Declarations of locals.

View file

@ -1231,7 +1231,12 @@ fn create_coroutine_drop_shim<'tcx>(
drop_clean: BasicBlock,
) -> Body<'tcx> {
let mut body = body.clone();
body.arg_count = 1; // make sure the resume argument is not included here
// Take the coroutine info out of the body, since the drop shim is
// not a coroutine body itself; it just has its drop built out of it.
let _ = body.coroutine.take();
// Make sure the resume argument is not included here, since we're
// building a body for `drop_in_place`.
body.arg_count = 1;
let source_info = SourceInfo::outermost(body.span);

File diff suppressed because it is too large Load diff

View file

@ -2349,112 +2349,151 @@ fn test_cursor() {
let map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
let mut cur = map.lower_bound(Bound::Unbounded);
assert_eq!(cur.key(), Some(&1));
cur.move_next();
assert_eq!(cur.key(), Some(&2));
assert_eq!(cur.peek_next(), Some((&3, &'c')));
cur.move_prev();
assert_eq!(cur.key(), Some(&1));
assert_eq!(cur.peek_next(), Some((&1, &'a')));
assert_eq!(cur.peek_prev(), None);
assert_eq!(cur.prev(), None);
assert_eq!(cur.next(), Some((&1, &'a')));
assert_eq!(cur.next(), Some((&2, &'b')));
assert_eq!(cur.peek_next(), Some((&3, &'c')));
assert_eq!(cur.prev(), Some((&2, &'b')));
assert_eq!(cur.peek_prev(), Some((&1, &'a')));
let mut cur = map.upper_bound(Bound::Excluded(&1));
assert_eq!(cur.key(), None);
cur.move_next();
assert_eq!(cur.key(), Some(&1));
cur.move_prev();
assert_eq!(cur.key(), None);
assert_eq!(cur.peek_prev(), Some((&3, &'c')));
assert_eq!(cur.peek_prev(), None);
assert_eq!(cur.next(), Some((&1, &'a')));
assert_eq!(cur.prev(), Some((&1, &'a')));
}
#[test]
fn test_cursor_mut() {
let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]);
let mut cur = map.lower_bound_mut(Bound::Excluded(&3));
assert_eq!(cur.key(), Some(&5));
cur.insert_before(4, 'd');
assert_eq!(cur.key(), Some(&5));
assert_eq!(cur.peek_next(), Some((&5, &mut 'e')));
assert_eq!(cur.peek_prev(), Some((&3, &mut 'c')));
cur.insert_before(4, 'd').unwrap();
assert_eq!(cur.peek_next(), Some((&5, &mut 'e')));
assert_eq!(cur.peek_prev(), Some((&4, &mut 'd')));
cur.move_next();
assert_eq!(cur.key(), None);
cur.insert_before(6, 'f');
assert_eq!(cur.key(), None);
assert_eq!(cur.remove_current(), None);
assert_eq!(cur.key(), None);
cur.insert_after(0, '?');
assert_eq!(cur.key(), None);
assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd'), (5, 'e'), (6, 'f')]));
assert_eq!(cur.next(), Some((&5, &mut 'e')));
assert_eq!(cur.peek_next(), None);
assert_eq!(cur.peek_prev(), Some((&5, &mut 'e')));
cur.insert_before(6, 'f').unwrap();
assert_eq!(cur.peek_next(), None);
assert_eq!(cur.peek_prev(), Some((&6, &mut 'f')));
assert_eq!(cur.remove_prev(), Some((6, 'f')));
assert_eq!(cur.remove_prev(), Some((5, 'e')));
assert_eq!(cur.remove_next(), None);
assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c'), (4, 'd')]));
let mut cur = map.upper_bound_mut(Bound::Included(&5));
assert_eq!(cur.key(), Some(&5));
assert_eq!(cur.remove_current(), Some((5, 'e')));
assert_eq!(cur.key(), Some(&6));
assert_eq!(cur.remove_current_and_move_back(), Some((6, 'f')));
assert_eq!(cur.key(), Some(&4));
assert_eq!(map, BTreeMap::from([(0, '?'), (1, 'a'), (3, 'c'), (4, 'd')]));
assert_eq!(cur.peek_next(), None);
assert_eq!(cur.prev(), Some((&4, &mut 'd')));
assert_eq!(cur.peek_next(), Some((&4, &mut 'd')));
assert_eq!(cur.peek_prev(), Some((&3, &mut 'c')));
assert_eq!(cur.remove_next(), Some((4, 'd')));
assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c')]));
}
#[test]
fn test_cursor_mut_key() {
let mut map = BTreeMap::from([(1, 'a'), (3, 'c'), (5, 'e')]);
let mut cur = unsafe { map.lower_bound_mut(Bound::Excluded(&3)).with_mutable_key() };
assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e')));
assert_eq!(cur.peek_prev(), Some((&mut 3, &mut 'c')));
cur.insert_before(4, 'd').unwrap();
assert_eq!(cur.peek_next(), Some((&mut 5, &mut 'e')));
assert_eq!(cur.peek_prev(), Some((&mut 4, &mut 'd')));
assert_eq!(cur.next(), Some((&mut 5, &mut 'e')));
assert_eq!(cur.peek_next(), None);
assert_eq!(cur.peek_prev(), Some((&mut 5, &mut 'e')));
cur.insert_before(6, 'f').unwrap();
assert_eq!(cur.peek_next(), None);
assert_eq!(cur.peek_prev(), Some((&mut 6, &mut 'f')));
assert_eq!(cur.remove_prev(), Some((6, 'f')));
assert_eq!(cur.remove_prev(), Some((5, 'e')));
assert_eq!(cur.remove_next(), None);
assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c'), (4, 'd')]));
let mut cur = unsafe { map.upper_bound_mut(Bound::Included(&5)).with_mutable_key() };
assert_eq!(cur.peek_next(), None);
assert_eq!(cur.prev(), Some((&mut 4, &mut 'd')));
assert_eq!(cur.peek_next(), Some((&mut 4, &mut 'd')));
assert_eq!(cur.peek_prev(), Some((&mut 3, &mut 'c')));
assert_eq!(cur.remove_next(), Some((4, 'd')));
assert_eq!(map, BTreeMap::from([(1, 'a'), (3, 'c')]));
}
#[test]
fn test_cursor_empty() {
let mut map = BTreeMap::new();
let mut cur = map.lower_bound_mut(Bound::Excluded(&3));
assert_eq!(cur.peek_next(), None);
assert_eq!(cur.peek_prev(), None);
cur.insert_after(0, 0).unwrap();
assert_eq!(cur.peek_next(), Some((&0, &mut 0)));
assert_eq!(cur.peek_prev(), None);
assert_eq!(map, BTreeMap::from([(0, 0)]));
}
#[should_panic(expected = "key must be ordered above the previous element")]
#[test]
fn test_cursor_mut_insert_before_1() {
let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
let mut cur = map.upper_bound_mut(Bound::Included(&2));
cur.insert_before(0, 'd');
cur.insert_before(0, 'd').unwrap_err();
}
#[should_panic(expected = "key must be ordered above the previous element")]
#[test]
fn test_cursor_mut_insert_before_2() {
let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
let mut cur = map.upper_bound_mut(Bound::Included(&2));
cur.insert_before(1, 'd');
cur.insert_before(1, 'd').unwrap_err();
}
#[should_panic(expected = "key must be ordered below the current element")]
#[test]
fn test_cursor_mut_insert_before_3() {
let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
let mut cur = map.upper_bound_mut(Bound::Included(&2));
cur.insert_before(2, 'd');
cur.insert_before(2, 'd').unwrap_err();
}
#[should_panic(expected = "key must be ordered below the current element")]
#[test]
fn test_cursor_mut_insert_before_4() {
let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
let mut cur = map.upper_bound_mut(Bound::Included(&2));
cur.insert_before(3, 'd');
cur.insert_before(3, 'd').unwrap_err();
}
#[should_panic(expected = "key must be ordered above the current element")]
#[test]
fn test_cursor_mut_insert_after_1() {
let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
let mut cur = map.upper_bound_mut(Bound::Included(&2));
cur.insert_after(1, 'd');
cur.insert_after(1, 'd').unwrap_err();
}
#[should_panic(expected = "key must be ordered above the current element")]
#[test]
fn test_cursor_mut_insert_after_2() {
let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
let mut cur = map.upper_bound_mut(Bound::Included(&2));
cur.insert_after(2, 'd');
cur.insert_after(2, 'd').unwrap_err();
}
#[should_panic(expected = "key must be ordered below the next element")]
#[test]
fn test_cursor_mut_insert_after_3() {
let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
let mut cur = map.upper_bound_mut(Bound::Included(&2));
cur.insert_after(3, 'd');
cur.insert_after(3, 'd').unwrap_err();
}
#[should_panic(expected = "key must be ordered below the next element")]
#[test]
fn test_cursor_mut_insert_after_4() {
let mut map = BTreeMap::from([(1, 'a'), (2, 'b'), (3, 'c')]);
let mut cur = map.upper_bound_mut(Bound::Included(&2));
cur.insert_after(4, 'd');
cur.insert_after(4, 'd').unwrap_err();
}
#[test]
@ -2462,14 +2501,14 @@ fn cursor_peek_prev_agrees_with_cursor_mut() {
let mut map = BTreeMap::from([(1, 1), (2, 2), (3, 3)]);
let cursor = map.lower_bound(Bound::Excluded(&3));
assert!(cursor.key().is_none());
assert!(cursor.peek_next().is_none());
let prev = cursor.peek_prev();
assert_matches!(prev, Some((&3, _)));
// Shadow names so the two parts of this test match.
let mut cursor = map.lower_bound_mut(Bound::Excluded(&3));
assert!(cursor.key().is_none());
assert!(cursor.peek_next().is_none());
let prev = cursor.peek_prev();
assert_matches!(prev, Some((&3, _)));

View file

@ -648,17 +648,36 @@ impl<K, V, Type> NodeRef<marker::Owned, K, V, Type> {
impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Leaf> {
/// Adds a key-value pair to the end of the node, and returns
/// the mutable reference of the inserted value.
pub fn push(&mut self, key: K, val: V) -> &mut V {
/// a handle to the inserted value.
///
/// # Safety
///
/// The returned handle has an unbound lifetime.
pub unsafe fn push_with_handle<'b>(
&mut self,
key: K,
val: V,
) -> Handle<NodeRef<marker::Mut<'b>, K, V, marker::Leaf>, marker::KV> {
let len = self.len_mut();
let idx = usize::from(*len);
assert!(idx < CAPACITY);
*len += 1;
unsafe {
self.key_area_mut(idx).write(key);
self.val_area_mut(idx).write(val)
self.val_area_mut(idx).write(val);
Handle::new_kv(
NodeRef { height: self.height, node: self.node, _marker: PhantomData },
idx,
)
}
}
/// Adds a key-value pair to the end of the node, and returns
/// the mutable reference of the inserted value.
pub fn push(&mut self, key: K, val: V) -> *mut V {
// SAFETY: The unbound handle is no longer accessible.
unsafe { self.push_with_handle(key, val).into_val_mut() }
}
}
impl<'a, K: 'a, V: 'a> NodeRef<marker::Mut<'a>, K, V, marker::Internal> {
@ -1100,10 +1119,10 @@ impl<'a, K: 'a, V: 'a, NodeType> Handle<NodeRef<marker::Mut<'a>, K, V, NodeType>
unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }
}
pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) {
pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) {
debug_assert!(self.idx < self.node.len());
let leaf = self.node.into_leaf_mut();
let k = unsafe { leaf.keys.get_unchecked(self.idx).assume_init_ref() };
let k = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() };
let v = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() };
(k, v)
}

View file

@ -220,7 +220,7 @@ impl<T: ?Sized> *const T {
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
///
/// Using this method means that code is *not* following [Strict
/// Provenance][../index.html#strict-provenance] rules. Supporting
/// Provenance][super#strict-provenance] rules. Supporting
/// [`from_exposed_addr`][] complicates specification and reasoning and may not be supported by
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
/// use [`addr`][pointer::addr] wherever possible.
@ -232,7 +232,7 @@ impl<T: ?Sized> *const T {
/// available.
///
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
/// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
///
/// [`from_exposed_addr`]: from_exposed_addr
#[must_use]

View file

@ -649,7 +649,7 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
/// address makes sense in the address space that this pointer will be used with.
///
/// Using this function means that code is *not* following [Strict
/// Provenance][../index.html#strict-provenance] rules. "Guessing" a
/// Provenance][self#strict-provenance] rules. "Guessing" a
/// suitable provenance complicates specification and reasoning and may not be supported by
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
/// use [`with_addr`][pointer::with_addr] wherever possible.
@ -660,7 +660,7 @@ pub const fn invalid_mut<T>(addr: usize) -> *mut T {
/// pointer has to pick up.
///
/// It is unclear whether this function can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance].
#[must_use]
#[inline(always)]
#[unstable(feature = "exposed_provenance", issue = "95228")]
@ -689,7 +689,7 @@ where
/// address makes sense in the address space that this pointer will be used with.
///
/// Using this function means that code is *not* following [Strict
/// Provenance][../index.html#strict-provenance] rules. "Guessing" a
/// Provenance][self#strict-provenance] rules. "Guessing" a
/// suitable provenance complicates specification and reasoning and may not be supported by
/// tools that help you to stay conformant with the Rust memory model, so it is recommended to
/// use [`with_addr`][pointer::with_addr] wherever possible.
@ -700,7 +700,7 @@ where
/// pointer has to pick up.
///
/// It is unclear whether this function can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
/// API and its claimed semantics are part of [Exposed Provenance][self#exposed-provenance].
#[must_use]
#[inline(always)]
#[unstable(feature = "exposed_provenance", issue = "95228")]

View file

@ -227,7 +227,7 @@ impl<T: ?Sized> *mut T {
/// provenance. (Reconstructing address space information, if required, is your responsibility.)
///
/// Using this method means that code is *not* following [Strict
/// Provenance][../index.html#strict-provenance] rules. Supporting
/// Provenance][super#strict-provenance] rules. Supporting
/// [`from_exposed_addr_mut`][] complicates specification and reasoning and may not be supported
/// by tools that help you to stay conformant with the Rust memory model, so it is recommended
/// to use [`addr`][pointer::addr] wherever possible.
@ -239,7 +239,7 @@ impl<T: ?Sized> *mut T {
/// available.
///
/// It is unclear whether this method can be given a satisfying unambiguous specification. This
/// API and its claimed semantics are part of [Exposed Provenance][../index.html#exposed-provenance].
/// API and its claimed semantics are part of [Exposed Provenance][super#exposed-provenance].
///
/// [`from_exposed_addr_mut`]: from_exposed_addr_mut
#[must_use]

View file

@ -149,8 +149,7 @@ pub trait CommandExt: Sealed {
/// The pidfd can be retrieved from the child with [`pidfd`] or [`take_pidfd`].
///
/// A pidfd will only be created if it is possible to do so
/// in a guaranteed race-free manner (e.g. if the `clone3` system call
/// is supported). Otherwise, [`pidfd`] will return an error.
/// in a guaranteed race-free manner. Otherwise, [`pidfd`] will return an error.
///
/// If a pidfd has been successfully created and not been taken from the `Child`
/// then calls to `kill()`, `wait()` and `try_wait()` will use the pidfd

View file

@ -147,8 +147,7 @@ impl Command {
#[cfg(not(target_os = "linux"))]
let pidfd = -1;
// Safety: We obtained the pidfd from calling `clone3` with
// `CLONE_PIDFD` so it's valid an otherwise unowned.
// Safety: We obtained the pidfd (on Linux) using SOCK_SEQPACKET, so it's valid.
let mut p = unsafe { Process::new(pid, pidfd) };
let mut bytes = [0; 8];

View file

@ -62,13 +62,14 @@ fn test_command_fork_no_unwind() {
}
#[test]
#[cfg(target_os = "linux")]
#[cfg(target_os = "linux")] // pidfds are a linux-specific concept
fn test_command_pidfd() {
use crate::assert_matches::assert_matches;
use crate::os::fd::{AsRawFd, RawFd};
use crate::os::linux::process::{ChildExt, CommandExt};
use crate::process::Command;
// pidfds require the pidfd_open syscall
let our_pid = crate::process::id();
let pidfd = unsafe { libc::syscall(libc::SYS_pidfd_open, our_pid, 0) };
let pidfd_open_available = if pidfd >= 0 {
@ -81,7 +82,9 @@ fn test_command_pidfd() {
// always exercise creation attempts
let mut child = Command::new("false").create_pidfd(true).spawn().unwrap();
// but only check if we know that the kernel supports pidfds
// but only check if we know that the kernel supports pidfds.
// We don't assert the precise value, since the standard library
// might have opened other file descriptors before our code runs.
if pidfd_open_available {
assert!(child.pidfd().is_ok());
}
@ -97,4 +100,17 @@ fn test_command_pidfd() {
child.kill().expect("failed to kill child");
let status = child.wait().expect("error waiting on pidfd");
assert_eq!(status.signal(), Some(libc::SIGKILL));
let _ = Command::new("echo")
.create_pidfd(false)
.spawn()
.unwrap()
.pidfd()
.expect_err("pidfd should not have been created when create_pid(false) is set");
let _ = Command::new("echo")
.spawn()
.unwrap()
.pidfd()
.expect_err("pidfd should not have been created");
}

View file

@ -106,7 +106,18 @@ mod imp {
// supported on the current kernel.
//
// Also fall back in case it is disabled by something like
// seccomp or inside of virtual machines.
// seccomp or inside of docker.
//
// If the `getrandom` syscall is not implemented in the current kernel version it should return an
// `ENOSYS` error. Docker also blocks the whole syscall inside unprivileged containers, and
// returns `EPERM` (instead of `ENOSYS`) when a program tries to invoke the syscall. Because of
// that we need to check for *both* `ENOSYS` and `EPERM`.
//
// Note that Docker's behavior is breaking other projects (notably glibc), so they're planning
// to update their filtering to return `ENOSYS` in a future release:
//
// https://github.com/moby/moby/issues/42680
//
GETRANDOM_UNAVAILABLE.store(true, Ordering::Relaxed);
return false;
} else if err == libc::EAGAIN {

View file

@ -364,7 +364,4 @@ pub mod netc {
pub sin6_flowinfo: u32,
pub sin6_scope_id: u32,
}
#[derive(Copy, Clone)]
pub struct sockaddr {}
}

View file

@ -1,8 +1,8 @@
<pre class="rust item-decl"><code>
{{ self.render_attributes_in_pre() | safe }}
{{ self.render_union() | safe }}
{{ self.render_attributes_in_pre()|safe }}
{{ self.render_union()|safe }}
</code></pre>
{{ self.document() | safe }}
{{ self.document()|safe }}
{% if self.fields_iter().peek().is_some() %}
<h2 id="fields" class="fields section-header"> {# #}
Fields<a href="#fields" class="anchor">§</a> {# #}
@ -12,13 +12,13 @@
<span id="structfield.{{ name }}" {#+ #}
class="{{ ItemType::StructField +}} section-header"> {# #}
<a href="#structfield.{{ name }}" class="anchor field">§</a> {# #}
<code>{{ name }}: {{+ self.print_ty(ty) | safe }}</code> {# #}
<code>{{ name }}: {{+ self.print_ty(ty)|safe }}</code> {# #}
</span>
{% if let Some(stability_class) = self.stability_field(field) %}
<span class="stab {{ stability_class }}"></span>
{% endif %}
{{ self.document_field(field) | safe }}
{{ self.document_field(field)|safe }}
{% endfor %}
{% endif %}
{{ self.render_assoc_items() | safe }}
{{ self.document_type_layout() | safe }}
{{ self.render_assoc_items()|safe }}
{{ self.document_type_layout()|safe }}

View file

@ -1,25 +1,4 @@
// MIR for `main::{closure#0}` 0 coroutine_drop
/* coroutine_layout = CoroutineLayout {
field_tys: {
_0: CoroutineSavedTy {
ty: std::string::String,
source_info: SourceInfo {
span: $DIR/coroutine_drop_cleanup.rs:12:13: 12:15 (#0),
scope: scope[0],
},
ignore_for_traits: false,
},
},
variant_fields: {
Unresumed(0): [],
Returned (1): [],
Panicked (2): [],
Suspend0 (3): [_0],
},
storage_conflicts: BitMatrix(1x1) {
(_0, _0),
},
} */
fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () {
let mut _0: ();

View file

@ -1,25 +1,4 @@
// MIR for `main::{closure#0}` 0 coroutine_drop
/* coroutine_layout = CoroutineLayout {
field_tys: {
_0: CoroutineSavedTy {
ty: std::string::String,
source_info: SourceInfo {
span: $DIR/coroutine_drop_cleanup.rs:12:13: 12:15 (#0),
scope: scope[0],
},
ignore_for_traits: false,
},
},
variant_fields: {
Unresumed(0): [],
Returned (1): [],
Panicked (2): [],
Suspend0 (3): [_0],
},
storage_conflicts: BitMatrix(1x1) {
(_0, _0),
},
} */
fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:11:15: 11:17}) -> () {
let mut _0: ();

View file

@ -1,56 +0,0 @@
// run-pass
// only-linux - pidfds are a linux-specific concept
#![feature(linux_pidfd)]
#![feature(rustc_private)]
extern crate libc;
use std::io::Error;
use std::os::linux::process::{ChildExt, CommandExt};
use std::process::Command;
fn has_clone3() -> bool {
let res = unsafe { libc::syscall(libc::SYS_clone3, 0, 0) };
let err = (res == -1)
.then(|| Error::last_os_error())
.expect("probe syscall should not succeed");
// If the `clone3` syscall is not implemented in the current kernel version it should return an
// `ENOSYS` error. Docker also blocks the whole syscall inside unprivileged containers, and
// returns `EPERM` (instead of `ENOSYS`) when a program tries to invoke the syscall. Because of
// that we need to check for *both* `ENOSYS` and `EPERM`.
//
// Note that Docker's behavior is breaking other projects (notably glibc), so they're planning
// to update their filtering to return `ENOSYS` in a future release:
//
// https://github.com/moby/moby/issues/42680
//
err.raw_os_error() != Some(libc::ENOSYS) && err.raw_os_error() != Some(libc::EPERM)
}
fn main() {
// pidfds require the clone3 syscall
if !has_clone3() {
return;
}
// We don't assert the precise value, since the standard library
// might have opened other file descriptors before our code runs.
let _ = Command::new("echo")
.create_pidfd(true)
.spawn()
.unwrap()
.pidfd().expect("failed to obtain pidfd");
let _ = Command::new("echo")
.create_pidfd(false)
.spawn()
.unwrap()
.pidfd().expect_err("pidfd should not have been created when create_pid(false) is set");
let _ = Command::new("echo")
.spawn()
.unwrap()
.pidfd().expect_err("pidfd should not have been created");
}