Auto merge of #98265 - JohnTitor:rollup-wtfqc4g, r=JohnTitor
Rollup of 4 pull requests Successful merges: - #95534 (Add `core::mem::copy` to complement `core::mem::drop`.) - #97912 (Stabilize `Path::try_exists()` and improve doc) - #98225 (Make debug_triple depend on target json file content rather than file path) - #98257 (Fix typos in `IntoFuture` docs) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
17c6bde14e
@ -1,6 +1,5 @@
|
||||
#![feature(let_chains)]
|
||||
#![feature(once_cell)]
|
||||
#![feature(path_try_exists)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
|
@ -39,11 +39,13 @@ use crate::json::{Json, ToJson};
|
||||
use crate::spec::abi::{lookup as lookup_abi, Abi};
|
||||
use crate::spec::crt_objects::{CrtObjects, CrtObjectsFallback};
|
||||
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
|
||||
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use serde_json::Value;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::TryFrom;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter::FromIterator;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::path::{Path, PathBuf};
|
||||
@ -2183,7 +2185,7 @@ impl Target {
|
||||
TargetTriple::TargetTriple(ref target_triple) => {
|
||||
load_builtin(target_triple).expect("built-in target")
|
||||
}
|
||||
TargetTriple::TargetPath(..) => {
|
||||
TargetTriple::TargetJson { .. } => {
|
||||
panic!("built-in targets doens't support target-paths")
|
||||
}
|
||||
}
|
||||
@ -2248,11 +2250,9 @@ impl Target {
|
||||
|
||||
Err(format!("Could not find specification for target {:?}", target_triple))
|
||||
}
|
||||
TargetTriple::TargetPath(ref target_path) => {
|
||||
if target_path.is_file() {
|
||||
return load_file(&target_path);
|
||||
}
|
||||
Err(format!("Target path {:?} is not a valid file", target_path))
|
||||
TargetTriple::TargetJson { ref contents, .. } => {
|
||||
let obj = serde_json::from_str(contents).map_err(|e| e.to_string())?;
|
||||
Target::from_json(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2421,10 +2421,77 @@ impl ToJson for Target {
|
||||
}
|
||||
|
||||
/// Either a target triple string or a path to a JSON file.
|
||||
#[derive(PartialEq, Clone, Debug, Hash, Encodable, Decodable)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum TargetTriple {
|
||||
TargetTriple(String),
|
||||
TargetPath(PathBuf),
|
||||
TargetJson {
|
||||
/// Warning: This field may only be used by rustdoc. Using it anywhere else will lead to
|
||||
/// inconsistencies as it is discarded during serialization.
|
||||
path_for_rustdoc: PathBuf,
|
||||
triple: String,
|
||||
contents: String,
|
||||
},
|
||||
}
|
||||
|
||||
// Use a manual implementation to ignore the path field
|
||||
impl PartialEq for TargetTriple {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
match (self, other) {
|
||||
(Self::TargetTriple(l0), Self::TargetTriple(r0)) => l0 == r0,
|
||||
(
|
||||
Self::TargetJson { path_for_rustdoc: _, triple: l_triple, contents: l_contents },
|
||||
Self::TargetJson { path_for_rustdoc: _, triple: r_triple, contents: r_contents },
|
||||
) => l_triple == r_triple && l_contents == r_contents,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use a manual implementation to ignore the path field
|
||||
impl Hash for TargetTriple {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) -> () {
|
||||
match self {
|
||||
TargetTriple::TargetTriple(triple) => {
|
||||
0u8.hash(state);
|
||||
triple.hash(state)
|
||||
}
|
||||
TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => {
|
||||
1u8.hash(state);
|
||||
triple.hash(state);
|
||||
contents.hash(state)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use a manual implementation to prevent encoding the target json file path in the crate metadata
|
||||
impl<S: Encoder> Encodable<S> for TargetTriple {
|
||||
fn encode(&self, s: &mut S) {
|
||||
match self {
|
||||
TargetTriple::TargetTriple(triple) => s.emit_enum_variant(0, |s| s.emit_str(triple)),
|
||||
TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents } => s
|
||||
.emit_enum_variant(1, |s| {
|
||||
s.emit_str(triple);
|
||||
s.emit_str(contents)
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D: Decoder> Decodable<D> for TargetTriple {
|
||||
fn decode(d: &mut D) -> Self {
|
||||
match d.read_usize() {
|
||||
0 => TargetTriple::TargetTriple(d.read_str().to_owned()),
|
||||
1 => TargetTriple::TargetJson {
|
||||
path_for_rustdoc: PathBuf::new(),
|
||||
triple: d.read_str().to_owned(),
|
||||
contents: d.read_str().to_owned(),
|
||||
},
|
||||
_ => {
|
||||
panic!("invalid enum variant tag while decoding `TargetTriple`, expected 0..2");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TargetTriple {
|
||||
@ -2436,7 +2503,19 @@ impl TargetTriple {
|
||||
/// Creates a target triple from the passed target path.
|
||||
pub fn from_path(path: &Path) -> Result<Self, io::Error> {
|
||||
let canonicalized_path = path.canonicalize()?;
|
||||
Ok(TargetTriple::TargetPath(canonicalized_path))
|
||||
let contents = std::fs::read_to_string(&canonicalized_path).map_err(|err| {
|
||||
io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!("target path {:?} is not a valid file: {}", canonicalized_path, err),
|
||||
)
|
||||
})?;
|
||||
let triple = canonicalized_path
|
||||
.file_stem()
|
||||
.expect("target path must not be empty")
|
||||
.to_str()
|
||||
.expect("target path must be valid unicode")
|
||||
.to_owned();
|
||||
Ok(TargetTriple::TargetJson { path_for_rustdoc: canonicalized_path, triple, contents })
|
||||
}
|
||||
|
||||
/// Returns a string triple for this target.
|
||||
@ -2444,12 +2523,8 @@ impl TargetTriple {
|
||||
/// If this target is a path, the file name (without extension) is returned.
|
||||
pub fn triple(&self) -> &str {
|
||||
match *self {
|
||||
TargetTriple::TargetTriple(ref triple) => triple,
|
||||
TargetTriple::TargetPath(ref path) => path
|
||||
.file_stem()
|
||||
.expect("target path must not be empty")
|
||||
.to_str()
|
||||
.expect("target path must be valid unicode"),
|
||||
TargetTriple::TargetTriple(ref triple)
|
||||
| TargetTriple::TargetJson { ref triple, .. } => triple,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2459,16 +2534,15 @@ impl TargetTriple {
|
||||
/// by `triple()`.
|
||||
pub fn debug_triple(&self) -> String {
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
|
||||
let triple = self.triple();
|
||||
if let TargetTriple::TargetPath(ref path) = *self {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
path.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
format!("{}-{}", triple, hash)
|
||||
} else {
|
||||
triple.into()
|
||||
match self {
|
||||
TargetTriple::TargetTriple(triple) => triple.to_owned(),
|
||||
TargetTriple::TargetJson { path_for_rustdoc: _, triple, contents: content } => {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
content.hash(&mut hasher);
|
||||
let hash = hasher.finish();
|
||||
format!("{}-{}", triple, hash)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::future::Future;
|
||||
|
||||
/// Conversion into a `Future`.
|
||||
///
|
||||
/// By implementing `Intofuture` for a type, you define how it will be
|
||||
/// By implementing `IntoFuture` for a type, you define how it will be
|
||||
/// converted to a future.
|
||||
///
|
||||
/// # `.await` desugaring
|
||||
@ -29,7 +29,7 @@ use crate::future::Future;
|
||||
/// When implementing futures manually there will often be a choice between
|
||||
/// implementing `Future` or `IntoFuture` for a type. Implementing `Future` is a
|
||||
/// good choice in most cases. But implementing `IntoFuture` is most useful when
|
||||
/// implementing "async builder" types, which allows the type to be modified
|
||||
/// implementing "async builder" types, which allow their values to be modified
|
||||
/// multiple times before being `.await`ed.
|
||||
///
|
||||
/// ```rust
|
||||
|
@ -973,6 +973,28 @@ pub const fn replace<T>(dest: &mut T, src: T) -> T {
|
||||
#[cfg_attr(not(test), rustc_diagnostic_item = "mem_drop")]
|
||||
pub fn drop<T>(_x: T) {}
|
||||
|
||||
/// Bitwise-copies a value.
|
||||
///
|
||||
/// This function is not magic; it is literally defined as
|
||||
/// ```
|
||||
/// pub fn copy<T: Copy>(x: &T) -> T { *x }
|
||||
/// ```
|
||||
///
|
||||
/// It is useful when you want to pass a function pointer to a combinator, rather than defining a new closure.
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// #![feature(mem_copy_fn)]
|
||||
/// use core::mem::copy;
|
||||
/// let result_from_ffi_function: Result<(), &i32> = Err(&1);
|
||||
/// let result_copied: Result<(), i32> = result_from_ffi_function.map_err(copy);
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "mem_copy_fn", issue = "98262")]
|
||||
pub fn copy<T: Copy>(x: &T) -> T {
|
||||
*x
|
||||
}
|
||||
|
||||
/// Interprets `src` as having type `&U`, and then reads `src` without moving
|
||||
/// the contained value.
|
||||
///
|
||||
|
@ -2317,10 +2317,14 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
|
||||
/// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
|
||||
/// denied on some of the parent directories.)
|
||||
///
|
||||
/// Note that while this avoids some pitfalls of the `exists()` method, it still can not
|
||||
/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
|
||||
/// where those bugs are not an issue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(path_try_exists)]
|
||||
/// #![feature(fs_try_exists)]
|
||||
/// use std::fs;
|
||||
///
|
||||
/// assert!(!fs::try_exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt"));
|
||||
@ -2330,7 +2334,7 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder {
|
||||
/// [`Path::exists`]: crate::path::Path::exists
|
||||
// FIXME: stabilization should modify documentation of `exists()` to recommend this method
|
||||
// instead.
|
||||
#[unstable(feature = "path_try_exists", issue = "83186")]
|
||||
#[unstable(feature = "fs_try_exists", issue = "83186")]
|
||||
#[inline]
|
||||
pub fn try_exists<P: AsRef<Path>>(path: P) -> io::Result<bool> {
|
||||
fs_imp::try_exists(path.as_ref())
|
||||
|
@ -2705,6 +2705,9 @@ impl Path {
|
||||
|
||||
/// Returns `true` if the path points at an existing entity.
|
||||
///
|
||||
/// Warning: this method may be error-prone, consider using [`try_exists()`] instead!
|
||||
/// It also has a risk of introducing time-of-check to time-of-use (TOCTOU) bugs.
|
||||
///
|
||||
/// This function will traverse symbolic links to query information about the
|
||||
/// destination file.
|
||||
///
|
||||
@ -2721,7 +2724,9 @@ impl Path {
|
||||
/// # See Also
|
||||
///
|
||||
/// This is a convenience function that coerces errors to false. If you want to
|
||||
/// check errors, call [`fs::metadata`].
|
||||
/// check errors, call [`Path::try_exists`].
|
||||
///
|
||||
/// [`try_exists()`]: Self::try_exists
|
||||
#[stable(feature = "path_ext", since = "1.5.0")]
|
||||
#[must_use]
|
||||
#[inline]
|
||||
@ -2738,20 +2743,20 @@ impl Path {
|
||||
/// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission
|
||||
/// denied on some of the parent directories.)
|
||||
///
|
||||
/// Note that while this avoids some pitfalls of the `exists()` method, it still can not
|
||||
/// prevent time-of-check to time-of-use (TOCTOU) bugs. You should only use it in scenarios
|
||||
/// where those bugs are not an issue.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// #![feature(path_try_exists)]
|
||||
///
|
||||
/// use std::path::Path;
|
||||
/// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt"));
|
||||
/// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
|
||||
/// ```
|
||||
///
|
||||
/// [`exists()`]: Self::exists
|
||||
// FIXME: stabilization should modify documentation of `exists()` to recommend this method
|
||||
// instead.
|
||||
#[unstable(feature = "path_try_exists", issue = "83186")]
|
||||
#[stable(feature = "path_try_exists", since = "1.63.0")]
|
||||
#[inline]
|
||||
pub fn try_exists(&self) -> io::Result<bool> {
|
||||
fs::try_exists(self)
|
||||
|
@ -365,8 +365,8 @@ fn run_test(
|
||||
}
|
||||
compiler.arg("--target").arg(match target {
|
||||
TargetTriple::TargetTriple(s) => s,
|
||||
TargetTriple::TargetPath(path) => {
|
||||
path.to_str().expect("target path must be valid unicode").to_string()
|
||||
TargetTriple::TargetJson { path_for_rustdoc, .. } => {
|
||||
path_for_rustdoc.to_str().expect("target path must be valid unicode").to_string()
|
||||
}
|
||||
});
|
||||
if let ErrorOutputType::HumanReadable(kind) = rustdoc_options.error_format {
|
||||
|
Loading…
x
Reference in New Issue
Block a user