mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 23:34:48 +00:00
Merge branch 'master' into issue-69276
This commit is contained in:
commit
2f311b07c8
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -34,6 +34,7 @@ jobs:
|
||||
CI_JOB_NAME: "${{ matrix.name }}"
|
||||
SCCACHE_BUCKET: rust-lang-gha-caches
|
||||
TOOLSTATE_REPO: "https://github.com/pietroalbini/rust-toolstate"
|
||||
CACHE_DOMAIN: ci-caches-gha.rust-lang.org
|
||||
if: "github.event_name == 'pull_request'"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -146,6 +147,7 @@ jobs:
|
||||
TOOLSTATE_PUBLISH: 1
|
||||
CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
|
||||
ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
|
||||
CACHE_DOMAIN: ci-caches-gha.rust-lang.org
|
||||
if: "github.event_name == 'push' && github.ref == 'refs/heads/try' && github.repository == 'rust-lang-ci/rust'"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -255,6 +257,7 @@ jobs:
|
||||
TOOLSTATE_PUBLISH: 1
|
||||
CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
|
||||
ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
|
||||
CACHE_DOMAIN: ci-caches-gha.rust-lang.org
|
||||
if: "github.event_name == 'push' && github.ref == 'refs/heads/auto' && github.repository == 'rust-lang-ci/rust'"
|
||||
strategy:
|
||||
matrix:
|
||||
@ -606,6 +609,7 @@ jobs:
|
||||
TOOLSTATE_PUBLISH: 1
|
||||
CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
|
||||
ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
|
||||
CACHE_DOMAIN: ci-caches-gha.rust-lang.org
|
||||
if: "github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'rust-lang-ci/rust'"
|
||||
steps:
|
||||
- name: checkout the source code
|
||||
|
91
Cargo.lock
91
Cargo.lock
@ -438,7 +438,7 @@ dependencies = [
|
||||
"proc-macro2 1.0.3",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.11",
|
||||
"synstructure 0.12.1",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -537,7 +537,6 @@ dependencies = [
|
||||
"compiletest_rs",
|
||||
"derive-new",
|
||||
"lazy_static 1.4.0",
|
||||
"regex",
|
||||
"rustc-workspace-hack",
|
||||
"rustc_tools_util 0.2.0",
|
||||
"semver",
|
||||
@ -938,13 +937,13 @@ checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
|
||||
|
||||
[[package]]
|
||||
name = "derive-new"
|
||||
version = "0.5.6"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ca414e896ae072546f4d789f452daaecf60ddee4c9df5dc6d5936d769e3d87c"
|
||||
checksum = "71f31892cd5c62e414316f2963c5689242c43d8e7bbcaaeca97e5e28c95d91d9"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.12",
|
||||
"syn 0.15.35",
|
||||
"proc-macro2 1.0.3",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1145,14 +1144,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "failure_derive"
|
||||
version = "0.1.5"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
|
||||
checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.12",
|
||||
"syn 0.15.35",
|
||||
"synstructure 0.10.2",
|
||||
"proc-macro2 1.0.3",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.11",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1405,30 +1404,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "handlebars"
|
||||
version = "2.0.1"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df044dd42cdb7e32f28557b661406fc0f2494be75199779998810dbc35030e0d"
|
||||
checksum = "ba758d094d31274eb49d15da6f326b96bf3185239a6359bf684f3d5321148900"
|
||||
dependencies = [
|
||||
"hashbrown 0.5.0",
|
||||
"lazy_static 1.4.0",
|
||||
"log",
|
||||
"pest",
|
||||
"pest_derive",
|
||||
"quick-error",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e1de41fb8dba9714efd92241565cdff73f78508c95697dd56787d3cba27e2353"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.6.2"
|
||||
@ -2055,9 +2042,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "mdbook"
|
||||
version = "0.3.5"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "031bdd9d4893c983e2f69ebc4b59070feee8276a584c4aabdcb351235ea28016"
|
||||
checksum = "e7ec525f7ebccc2dd935c263717250cd37f9a4b264a77c5dbc950ea2734d8159"
|
||||
dependencies = [
|
||||
"ammonia",
|
||||
"chrono",
|
||||
@ -2557,15 +2544,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "pest_generator"
|
||||
version = "2.1.0"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63120576c4efd69615b5537d3d052257328a4ca82876771d6944424ccfd9f646"
|
||||
checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55"
|
||||
dependencies = [
|
||||
"pest",
|
||||
"pest_meta",
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.12",
|
||||
"syn 0.15.35",
|
||||
"proc-macro2 1.0.3",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -2785,9 +2772,9 @@ checksum = "6ddd112cca70a4d30883b2d21568a1d376ff8be4758649f64f973c6845128ad3"
|
||||
|
||||
[[package]]
|
||||
name = "quick-error"
|
||||
version = "1.2.2"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
|
||||
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||
|
||||
[[package]]
|
||||
name = "quine-mc_cluskey"
|
||||
@ -3449,7 +3436,7 @@ dependencies = [
|
||||
"proc-macro2 1.0.3",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.11",
|
||||
"synstructure 0.12.1",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4059,7 +4046,7 @@ dependencies = [
|
||||
"proc-macro2 1.0.3",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.11",
|
||||
"synstructure 0.12.1",
|
||||
"synstructure",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4630,13 +4617,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.81"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "477b13b646f5b5b56fc95bedfc3b550d12141ce84f466f6c44b9a17589923885"
|
||||
checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.12",
|
||||
"syn 0.15.35",
|
||||
"proc-macro2 1.0.3",
|
||||
"quote 1.0.2",
|
||||
"syn 1.0.11",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -4778,9 +4765,9 @@ checksum = "ffbc596e092fe5f598b12ef46cc03754085ac2f4d8c739ad61c4ae266cc3b3fa"
|
||||
|
||||
[[package]]
|
||||
name = "stacker"
|
||||
version = "0.1.8"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32c2467b8abbb417e4e62fd62229719b9c9d77714a7fa989f1afad16ba9c9743"
|
||||
checksum = "72dd941b456e1c006d6b9f27c526d5b69281288aeea8cba82c19d3843d8ccdd2"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cfg-if",
|
||||
@ -4800,7 +4787,7 @@ dependencies = [
|
||||
"core",
|
||||
"dlmalloc",
|
||||
"fortanix-sgx-abi",
|
||||
"hashbrown 0.6.2",
|
||||
"hashbrown",
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"panic_abort",
|
||||
@ -4932,18 +4919,6 @@ dependencies = [
|
||||
"unicode-xid 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.30",
|
||||
"quote 0.6.12",
|
||||
"syn 0.15.35",
|
||||
"unicode-xid 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.12.1"
|
||||
|
@ -314,6 +314,10 @@
|
||||
# library.
|
||||
#debug-assertions = false
|
||||
|
||||
# Whether or not debug assertions are enabled for the standard library.
|
||||
# Overrides the `debug-assertions` option, if defined.
|
||||
#debug-assertions-std = false
|
||||
|
||||
# Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`.
|
||||
# `0` - no debug info
|
||||
# `1` - line tables only
|
||||
@ -411,10 +415,6 @@
|
||||
# sysroot.
|
||||
#llvm-tools = false
|
||||
|
||||
# Indicates whether LLDB will be made available in the sysroot.
|
||||
# This is only built if LLVM is also being built.
|
||||
#lldb = false
|
||||
|
||||
# Whether to deny warnings in crates
|
||||
#deny-warnings = true
|
||||
|
||||
|
@ -180,13 +180,16 @@ def format_build_time(duration):
|
||||
def default_build_triple():
|
||||
"""Build triple as in LLVM"""
|
||||
default_encoding = sys.getdefaultencoding()
|
||||
required = not sys.platform == 'win32'
|
||||
ostype = require(["uname", "-s"], exit=required).decode(default_encoding)
|
||||
cputype = require(['uname', '-m'], exit=required).decode(default_encoding)
|
||||
required = sys.platform != 'win32'
|
||||
ostype = require(["uname", "-s"], exit=required)
|
||||
cputype = require(['uname', '-m'], exit=required)
|
||||
|
||||
if ostype is None or cputype is None:
|
||||
return 'x86_64-pc-windows-msvc'
|
||||
|
||||
ostype = ostype.decode(default_encoding)
|
||||
cputype = cputype.decode(default_encoding)
|
||||
|
||||
# The goal here is to come up with the same triple as LLVM would,
|
||||
# at least for the subset of platforms we're willing to target.
|
||||
ostype_mapper = {
|
||||
|
@ -439,7 +439,6 @@ impl<'a> Builder<'a> {
|
||||
dist::Clippy,
|
||||
dist::Miri,
|
||||
dist::LlvmTools,
|
||||
dist::Lldb,
|
||||
dist::Extended,
|
||||
dist::HashSign
|
||||
),
|
||||
@ -916,7 +915,14 @@ impl<'a> Builder<'a> {
|
||||
.env("RUSTC", self.out.join("bootstrap/debug/rustc"))
|
||||
.env("RUSTC_REAL", self.rustc(compiler))
|
||||
.env("RUSTC_STAGE", stage.to_string())
|
||||
.env("RUSTC_DEBUG_ASSERTIONS", self.config.rust_debug_assertions.to_string())
|
||||
.env(
|
||||
"RUSTC_DEBUG_ASSERTIONS",
|
||||
if mode == Mode::Std {
|
||||
self.config.rust_debug_assertions_std.to_string()
|
||||
} else {
|
||||
self.config.rust_debug_assertions.to_string()
|
||||
},
|
||||
)
|
||||
.env("RUSTC_SYSROOT", &sysroot)
|
||||
.env("RUSTC_LIBDIR", &libdir)
|
||||
.env("RUSTDOC", self.out.join("bootstrap/debug/rustdoc"))
|
||||
|
@ -85,7 +85,6 @@ pub struct Config {
|
||||
|
||||
pub use_lld: bool,
|
||||
pub lld_enabled: bool,
|
||||
pub lldb_enabled: bool,
|
||||
pub llvm_tools_enabled: bool,
|
||||
|
||||
pub llvm_cflags: Option<String>,
|
||||
@ -98,6 +97,7 @@ pub struct Config {
|
||||
pub rust_codegen_units: Option<u32>,
|
||||
pub rust_codegen_units_std: Option<u32>,
|
||||
pub rust_debug_assertions: bool,
|
||||
pub rust_debug_assertions_std: bool,
|
||||
pub rust_debuginfo_level_rustc: u32,
|
||||
pub rust_debuginfo_level_std: u32,
|
||||
pub rust_debuginfo_level_tools: u32,
|
||||
@ -315,6 +315,7 @@ struct Rust {
|
||||
codegen_units: Option<u32>,
|
||||
codegen_units_std: Option<u32>,
|
||||
debug_assertions: Option<bool>,
|
||||
debug_assertions_std: Option<bool>,
|
||||
debuginfo_level: Option<u32>,
|
||||
debuginfo_level_rustc: Option<u32>,
|
||||
debuginfo_level_std: Option<u32>,
|
||||
@ -337,7 +338,6 @@ struct Rust {
|
||||
lld: Option<bool>,
|
||||
use_lld: Option<bool>,
|
||||
llvm_tools: Option<bool>,
|
||||
lldb: Option<bool>,
|
||||
deny_warnings: Option<bool>,
|
||||
backtrace_on_ice: Option<bool>,
|
||||
verify_llvm_ir: Option<bool>,
|
||||
@ -520,6 +520,7 @@ impl Config {
|
||||
let mut llvm_assertions = None;
|
||||
let mut debug = None;
|
||||
let mut debug_assertions = None;
|
||||
let mut debug_assertions_std = None;
|
||||
let mut debuginfo_level = None;
|
||||
let mut debuginfo_level_rustc = None;
|
||||
let mut debuginfo_level_std = None;
|
||||
@ -562,6 +563,7 @@ impl Config {
|
||||
if let Some(ref rust) = toml.rust {
|
||||
debug = rust.debug;
|
||||
debug_assertions = rust.debug_assertions;
|
||||
debug_assertions_std = rust.debug_assertions_std;
|
||||
debuginfo_level = rust.debuginfo_level;
|
||||
debuginfo_level_rustc = rust.debuginfo_level_rustc;
|
||||
debuginfo_level_std = rust.debuginfo_level_std;
|
||||
@ -585,7 +587,6 @@ impl Config {
|
||||
}
|
||||
set(&mut config.use_lld, rust.use_lld);
|
||||
set(&mut config.lld_enabled, rust.lld);
|
||||
set(&mut config.lldb_enabled, rust.lldb);
|
||||
set(&mut config.llvm_tools_enabled, rust.llvm_tools);
|
||||
config.rustc_parallel = rust.parallel_compiler.unwrap_or(false);
|
||||
config.rustc_default_linker = rust.default_linker.clone();
|
||||
@ -661,6 +662,8 @@ impl Config {
|
||||
|
||||
let default = debug == Some(true);
|
||||
config.rust_debug_assertions = debug_assertions.unwrap_or(default);
|
||||
config.rust_debug_assertions_std =
|
||||
debug_assertions_std.unwrap_or(config.rust_debug_assertions);
|
||||
|
||||
let with_defaults = |debuginfo_level_specific: Option<u32>| {
|
||||
debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) {
|
||||
|
@ -57,7 +57,6 @@ o("cargo-native-static", "build.cargo-native-static", "static native libraries i
|
||||
o("profiler", "build.profiler", "build the profiler runtime")
|
||||
o("full-tools", None, "enable all tools")
|
||||
o("lld", "rust.lld", "build lld")
|
||||
o("lldb", "rust.lldb", "build lldb")
|
||||
o("missing-tools", "dist.missing-tools", "allow failures when building tools")
|
||||
o("use-libcxx", "llvm.use-libcxx", "build LLVM with libc++")
|
||||
o("control-flow-guard", "rust.control-flow-guard", "Enable Control Flow Guard")
|
||||
|
@ -38,8 +38,6 @@ pub fn pkgname(builder: &Builder<'_>, component: &str) -> String {
|
||||
format!("{}-{}", component, builder.rustfmt_package_vers())
|
||||
} else if component == "llvm-tools" {
|
||||
format!("{}-{}", component, builder.llvm_tools_package_vers())
|
||||
} else if component == "lldb" {
|
||||
format!("{}-{}", component, builder.lldb_package_vers())
|
||||
} else {
|
||||
assert!(component.starts_with("rust"));
|
||||
format!("{}-{}", component, builder.rust_package_vers())
|
||||
@ -1645,7 +1643,6 @@ impl Step for Extended {
|
||||
let llvm_tools_installer = builder.ensure(LlvmTools { target });
|
||||
let clippy_installer = builder.ensure(Clippy { compiler, target });
|
||||
let miri_installer = builder.ensure(Miri { compiler, target });
|
||||
let lldb_installer = builder.ensure(Lldb { target });
|
||||
let mingw_installer = builder.ensure(Mingw { host: target });
|
||||
let analysis_installer = builder.ensure(Analysis { compiler, target });
|
||||
|
||||
@ -1681,7 +1678,6 @@ impl Step for Extended {
|
||||
tarballs.extend(miri_installer.clone());
|
||||
tarballs.extend(rustfmt_installer.clone());
|
||||
tarballs.extend(llvm_tools_installer);
|
||||
tarballs.extend(lldb_installer);
|
||||
tarballs.push(analysis_installer);
|
||||
tarballs.push(std_installer);
|
||||
if builder.config.docs {
|
||||
@ -2222,7 +2218,6 @@ impl Step for HashSign {
|
||||
cmd.arg(builder.package_vers(&builder.release_num("miri")));
|
||||
cmd.arg(builder.package_vers(&builder.release_num("rustfmt")));
|
||||
cmd.arg(builder.llvm_tools_package_vers());
|
||||
cmd.arg(builder.lldb_package_vers());
|
||||
|
||||
builder.create_dir(&distdir(builder));
|
||||
|
||||
@ -2349,119 +2344,3 @@ impl Step for LlvmTools {
|
||||
Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct Lldb {
|
||||
pub target: Interned<String>,
|
||||
}
|
||||
|
||||
impl Step for Lldb {
|
||||
type Output = Option<PathBuf>;
|
||||
const ONLY_HOSTS: bool = true;
|
||||
const DEFAULT: bool = true;
|
||||
|
||||
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
|
||||
run.path("src/llvm-project/lldb").path("src/tools/lldb")
|
||||
}
|
||||
|
||||
fn make_run(run: RunConfig<'_>) {
|
||||
run.builder.ensure(Lldb { target: run.target });
|
||||
}
|
||||
|
||||
fn run(self, builder: &Builder<'_>) -> Option<PathBuf> {
|
||||
let target = self.target;
|
||||
|
||||
if builder.config.dry_run {
|
||||
return None;
|
||||
}
|
||||
|
||||
let bindir = builder.llvm_out(target).join("bin");
|
||||
let lldb_exe = bindir.join(exe("lldb", &target));
|
||||
if !lldb_exe.exists() {
|
||||
return None;
|
||||
}
|
||||
|
||||
builder.info(&format!("Dist Lldb ({})", target));
|
||||
let src = builder.src.join("src/llvm-project/lldb");
|
||||
let name = pkgname(builder, "lldb");
|
||||
|
||||
let tmp = tmpdir(builder);
|
||||
let image = tmp.join("lldb-image");
|
||||
drop(fs::remove_dir_all(&image));
|
||||
|
||||
// Prepare the image directory
|
||||
let root = image.join("lib/rustlib").join(&*target);
|
||||
let dst = root.join("bin");
|
||||
t!(fs::create_dir_all(&dst));
|
||||
for program in &["lldb", "lldb-argdumper", "lldb-mi", "lldb-server"] {
|
||||
let exe = bindir.join(exe(program, &target));
|
||||
builder.install(&exe, &dst, 0o755);
|
||||
}
|
||||
|
||||
// The libraries.
|
||||
let libdir = builder.llvm_out(target).join("lib");
|
||||
let dst = root.join("lib");
|
||||
t!(fs::create_dir_all(&dst));
|
||||
for entry in t!(fs::read_dir(&libdir)) {
|
||||
let entry = entry.unwrap();
|
||||
if let Ok(name) = entry.file_name().into_string() {
|
||||
if name.starts_with("liblldb.") && !name.ends_with(".a") {
|
||||
if t!(entry.file_type()).is_symlink() {
|
||||
builder.copy_to_folder(&entry.path(), &dst);
|
||||
} else {
|
||||
builder.install(&entry.path(), &dst, 0o755);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The lldb scripts might be installed in lib/python$version
|
||||
// or in lib64/python$version. If lib64 exists, use it;
|
||||
// otherwise lib.
|
||||
let libdir = builder.llvm_out(target).join("lib64");
|
||||
let (libdir, libdir_name) = if libdir.exists() {
|
||||
(libdir, "lib64")
|
||||
} else {
|
||||
(builder.llvm_out(target).join("lib"), "lib")
|
||||
};
|
||||
for entry in t!(fs::read_dir(&libdir)) {
|
||||
let entry = t!(entry);
|
||||
if let Ok(name) = entry.file_name().into_string() {
|
||||
if name.starts_with("python") {
|
||||
let dst = root.join(libdir_name).join(entry.file_name());
|
||||
t!(fs::create_dir_all(&dst));
|
||||
builder.cp_r(&entry.path(), &dst);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare the overlay
|
||||
let overlay = tmp.join("lldb-overlay");
|
||||
drop(fs::remove_dir_all(&overlay));
|
||||
builder.create_dir(&overlay);
|
||||
builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644);
|
||||
builder.create(&overlay.join("version"), &builder.lldb_vers());
|
||||
|
||||
// Generate the installer tarball
|
||||
let mut cmd = rust_installer(builder);
|
||||
cmd.arg("generate")
|
||||
.arg("--product-name=Rust")
|
||||
.arg("--rel-manifest-dir=rustlib")
|
||||
.arg("--success-message=lldb-installed.")
|
||||
.arg("--image-dir")
|
||||
.arg(&image)
|
||||
.arg("--work-dir")
|
||||
.arg(&tmpdir(builder))
|
||||
.arg("--output-dir")
|
||||
.arg(&distdir(builder))
|
||||
.arg("--non-installed-overlay")
|
||||
.arg(&overlay)
|
||||
.arg(format!("--package-name={}-{}", name, target))
|
||||
.arg("--legacy-manifest-dirs=rustlib,cargo")
|
||||
.arg("--component-name=lldb-preview");
|
||||
|
||||
builder.run(&mut cmd);
|
||||
Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target)))
|
||||
}
|
||||
}
|
||||
|
@ -503,6 +503,20 @@ Arguments:
|
||||
}
|
||||
};
|
||||
|
||||
if let Subcommand::Check { .. } = &cmd {
|
||||
if matches.opt_str("stage").is_some() {
|
||||
println!("{}", "--stage not supported for x.py check, always treated as stage 0");
|
||||
process::exit(1);
|
||||
}
|
||||
if matches.opt_str("keep-stage").is_some() {
|
||||
println!(
|
||||
"{}",
|
||||
"--keep-stage not supported for x.py check, only one stage available"
|
||||
);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
Flags {
|
||||
verbose: matches.opt_count("verbose"),
|
||||
stage: matches.opt_str("stage").map(|j| j.parse().expect("`stage` should be a number")),
|
||||
|
@ -23,7 +23,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, path: &Path, check: bool) {
|
||||
if !status.success() {
|
||||
eprintln!(
|
||||
"Running `{}` failed.\nIf you're running `tidy`, \
|
||||
try again with `--bless` flag. Or, you just want to format \
|
||||
try again with `--bless`. Or, if you just want to format \
|
||||
code, run `./x.py fmt` instead.",
|
||||
cmd_debug,
|
||||
);
|
||||
|
@ -1029,14 +1029,6 @@ impl Build {
|
||||
self.rust_version()
|
||||
}
|
||||
|
||||
fn lldb_package_vers(&self) -> String {
|
||||
self.package_vers(channel::CFG_RELEASE_NUM)
|
||||
}
|
||||
|
||||
fn lldb_vers(&self) -> String {
|
||||
self.rust_version()
|
||||
}
|
||||
|
||||
fn llvm_link_tools_dynamically(&self, target: Interned<String>) -> bool {
|
||||
target.contains("linux-gnu") || target.contains("apple-darwin")
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ impl Step for Llvm {
|
||||
}
|
||||
|
||||
// For distribution we want the LLVM tools to be *statically* linked to libstdc++
|
||||
if builder.config.llvm_tools_enabled || builder.config.lldb_enabled {
|
||||
if builder.config.llvm_tools_enabled {
|
||||
if !target.contains("msvc") {
|
||||
if target.contains("apple") {
|
||||
cfg.define("CMAKE_EXE_LINKER_FLAGS", "-static-libstdc++");
|
||||
@ -212,17 +212,9 @@ impl Step for Llvm {
|
||||
enabled_llvm_projects.push("compiler-rt");
|
||||
}
|
||||
|
||||
if builder.config.lldb_enabled {
|
||||
enabled_llvm_projects.push("clang");
|
||||
enabled_llvm_projects.push("lldb");
|
||||
// For the time being, disable code signing.
|
||||
cfg.define("LLDB_CODESIGN_IDENTITY", "");
|
||||
cfg.define("LLDB_NO_DEBUGSERVER", "ON");
|
||||
} else {
|
||||
// LLDB requires libxml2; but otherwise we want it to be disabled.
|
||||
// See https://github.com/rust-lang/rust/pull/50104
|
||||
cfg.define("LLVM_ENABLE_LIBXML2", "OFF");
|
||||
}
|
||||
// We want libxml to be disabled.
|
||||
// See https://github.com/rust-lang/rust/pull/50104
|
||||
cfg.define("LLVM_ENABLE_LIBXML2", "OFF");
|
||||
|
||||
if !enabled_llvm_projects.is_empty() {
|
||||
enabled_llvm_projects.sort();
|
||||
|
@ -117,14 +117,6 @@ pub fn check(build: &mut Build) {
|
||||
build.config.ninja = true;
|
||||
}
|
||||
}
|
||||
|
||||
if build.config.lldb_enabled {
|
||||
cmd_finder.must_have("swig");
|
||||
let out = output(Command::new("swig").arg("-version"));
|
||||
if !out.contains("SWIG Version 3") && !out.contains("SWIG Version 4") {
|
||||
panic!("Ensure that Swig 3.x.x or 4.x.x is installed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
build.config.python = build
|
||||
|
@ -436,7 +436,6 @@ impl Step for Miri {
|
||||
|
||||
// miri tests need to know about the stage sysroot
|
||||
cargo.env("MIRI_SYSROOT", miri_sysroot);
|
||||
cargo.env("RUSTC_TEST_SUITE", builder.rustc(compiler));
|
||||
cargo.env("RUSTC_LIB_PATH", builder.rustc_libdir(compiler));
|
||||
cargo.env("MIRI_PATH", miri);
|
||||
|
||||
@ -1097,20 +1096,15 @@ impl Step for Compiletest {
|
||||
.to_string()
|
||||
})
|
||||
};
|
||||
let lldb_exe = if builder.config.lldb_enabled {
|
||||
// Test against the lldb that was just built.
|
||||
builder.llvm_out(target).join("bin").join("lldb")
|
||||
} else {
|
||||
PathBuf::from("lldb")
|
||||
};
|
||||
let lldb_version = Command::new(&lldb_exe)
|
||||
let lldb_exe = "lldb";
|
||||
let lldb_version = Command::new(lldb_exe)
|
||||
.arg("--version")
|
||||
.output()
|
||||
.map(|output| String::from_utf8_lossy(&output.stdout).to_string())
|
||||
.ok();
|
||||
if let Some(ref vers) = lldb_version {
|
||||
cmd.arg("--lldb-version").arg(vers);
|
||||
let lldb_python_dir = run(Command::new(&lldb_exe).arg("-P")).ok();
|
||||
let lldb_python_dir = run(Command::new(lldb_exe).arg("-P")).ok();
|
||||
if let Some(ref dir) = lldb_python_dir {
|
||||
cmd.arg("--lldb-python-dir").arg(dir);
|
||||
}
|
||||
|
@ -17,6 +17,8 @@ dist=$objdir/build/dist
|
||||
|
||||
source "$ci_dir/shared.sh"
|
||||
|
||||
CACHE_DOMAIN="${CACHE_DOMAIN:-ci-caches.rust-lang.org}"
|
||||
|
||||
if [ -f "$docker_dir/$image/Dockerfile" ]; then
|
||||
if [ "$CI" != "" ]; then
|
||||
hash_key=/tmp/.docker-hash-key.txt
|
||||
@ -38,9 +40,7 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
|
||||
cksum=$(sha512sum $hash_key | \
|
||||
awk '{print $1}')
|
||||
|
||||
s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
|
||||
url="https://$SCCACHE_BUCKET.s3.amazonaws.com/docker/$cksum"
|
||||
upload="aws s3 cp - $s3url"
|
||||
url="https://$CACHE_DOMAIN/docker/$cksum"
|
||||
|
||||
echo "Attempting to download $url"
|
||||
rm -f /tmp/rustci_docker_cache
|
||||
@ -65,7 +65,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
|
||||
-f "$dockerfile" \
|
||||
"$context"
|
||||
|
||||
if [ "$upload" != "" ]; then
|
||||
if [ "$CI" != "" ]; then
|
||||
s3url="s3://$SCCACHE_BUCKET/docker/$cksum"
|
||||
upload="aws s3 cp - $s3url"
|
||||
digest=$(docker inspect rust-ci --format '{{.Id}}')
|
||||
echo "Built container $digest"
|
||||
if ! grep -q "$digest" <(echo "$loaded_images"); then
|
||||
|
@ -37,6 +37,7 @@ x--expand-yaml-anchors--remove:
|
||||
- &public-variables
|
||||
SCCACHE_BUCKET: rust-lang-gha-caches
|
||||
TOOLSTATE_REPO: https://github.com/pietroalbini/rust-toolstate
|
||||
CACHE_DOMAIN: ci-caches-gha.rust-lang.org
|
||||
|
||||
- &prod-variables
|
||||
SCCACHE_BUCKET: rust-lang-gha-caches
|
||||
@ -51,6 +52,7 @@ x--expand-yaml-anchors--remove:
|
||||
# (caches, artifacts...).
|
||||
CACHES_AWS_ACCESS_KEY_ID: AKIA46X5W6CZOMUQATD5
|
||||
ARTIFACTS_AWS_ACCESS_KEY_ID: AKIA46X5W6CZH5AYXDVF
|
||||
CACHE_DOMAIN: ci-caches-gha.rust-lang.org
|
||||
|
||||
- &base-job
|
||||
env: {}
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit e37c0e84e2ef73d3a4ebffda8011db6814a3b02d
|
||||
Subproject commit 6247be15a7f7509559f7981ee2209b9e0cc121df
|
@ -1 +1 @@
|
||||
Subproject commit 8204c1d123472cd17f0c1c5c77300ae802eb0271
|
||||
Subproject commit 49270740c7a4bff2763e6bc730b191d45b7d5167
|
@ -1 +1 @@
|
||||
Subproject commit 40beccdf1bb8eb9184a2e3b42db8b8c6e394247f
|
||||
Subproject commit 366c50a03bed928589771eba8a6f18e0c0c01d23
|
@ -1 +1 @@
|
||||
Subproject commit 4d2d275997746d35eabfc4d992dfbdcce2f626ed
|
||||
Subproject commit d1517d4e3f29264c5c67bce2658516bb5202c800
|
@ -1 +1 @@
|
||||
Subproject commit ed22e6fbfcb6ce436e9ea3b4bb4a55b2fb50a57e
|
||||
Subproject commit 892b928b565e35d25b6f9c47faee03b94bc41489
|
@ -1 +1 @@
|
||||
Subproject commit ffc99581689fe2455908aaef5f5cf50dd03bb8f5
|
||||
Subproject commit ab072b14393cbd9e8a1d1d75879bf51e27217bbb
|
@ -464,7 +464,15 @@ machine. Each target has a default base CPU.
|
||||
|
||||
Individual targets will support different features; this flag lets you control
|
||||
enabling or disabling a feature. Each feature should be prefixed with a `+` to
|
||||
enable it or `-` to disable it. Separate multiple features with commas.
|
||||
enable it or `-` to disable it.
|
||||
|
||||
Features from multiple `-C target-feature` options are combined. \
|
||||
Multiple features can be specified in a single option by separating them
|
||||
with commas - `-C target-feature=+x,-y`. \
|
||||
If some feature is specified more than once with both `+` and `-`,
|
||||
then values passed later override values passed earlier. \
|
||||
For example, `-C target-feature=+x,-y,+z -Ctarget-feature=-x,+y`
|
||||
is equivalent to `-C target-feature=-x,+y,+z`.
|
||||
|
||||
To see the valid options and an example of use, run `rustc --print
|
||||
target-features`.
|
||||
|
@ -23,7 +23,7 @@ fn allocate_zeroed() {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
|
||||
#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
|
||||
fn alloc_owned_small(b: &mut Bencher) {
|
||||
b.iter(|| {
|
||||
let _: Box<_> = box 10;
|
||||
|
@ -215,59 +215,6 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
|
||||
clone_subtree(self.root.as_ref().unwrap().as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_from(&mut self, other: &Self) {
|
||||
BTreeClone::clone_from(self, other);
|
||||
}
|
||||
}
|
||||
|
||||
trait BTreeClone {
|
||||
fn clone_from(&mut self, other: &Self);
|
||||
}
|
||||
|
||||
impl<K: Clone, V: Clone> BTreeClone for BTreeMap<K, V> {
|
||||
default fn clone_from(&mut self, other: &Self) {
|
||||
*self = other.clone();
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Clone + Ord, V: Clone> BTreeClone for BTreeMap<K, V> {
|
||||
fn clone_from(&mut self, other: &Self) {
|
||||
// This truncates `self` to `other.len()` by calling `split_off` on
|
||||
// the first key after `other.len()` elements if it exists.
|
||||
let split_off_key = if self.len() > other.len() {
|
||||
let diff = self.len() - other.len();
|
||||
if diff <= other.len() {
|
||||
self.iter().nth_back(diff - 1).map(|pair| (*pair.0).clone())
|
||||
} else {
|
||||
self.iter().nth(other.len()).map(|pair| (*pair.0).clone())
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
if let Some(key) = split_off_key {
|
||||
self.split_off(&key);
|
||||
}
|
||||
|
||||
let mut siter = self.range_mut(..);
|
||||
let mut oiter = other.iter();
|
||||
// After truncation, `self` is at most as long as `other` so this loop
|
||||
// replaces every key-value pair in `self`. Since `oiter` is in sorted
|
||||
// order and the structure of the `BTreeMap` stays the same,
|
||||
// the BTree invariants are maintained at the end of the loop.
|
||||
while !siter.is_empty() {
|
||||
if let Some((ok, ov)) = oiter.next() {
|
||||
// SAFETY: This is safe because `siter` is nonempty.
|
||||
let (sk, sv) = unsafe { siter.next_unchecked() };
|
||||
sk.clone_from(ok);
|
||||
sv.clone_from(ov);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If `other` is longer than `self`, the remaining elements are inserted.
|
||||
self.extend(oiter.map(|(k, v)| ((*k).clone(), (*v).clone())));
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, Q: ?Sized> super::Recover<Q> for BTreeMap<K, ()>
|
||||
|
@ -182,7 +182,6 @@ fn test_insert_prev() {
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support threads
|
||||
fn test_send() {
|
||||
let n = list_from(&[1, 2, 3]);
|
||||
thread::spawn(move || {
|
||||
|
@ -1354,7 +1354,9 @@ impl<T> VecDeque<T> {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn push_front(&mut self, value: T) {
|
||||
self.grow_if_necessary();
|
||||
if self.is_full() {
|
||||
self.grow();
|
||||
}
|
||||
|
||||
self.tail = self.wrap_sub(self.tail, 1);
|
||||
let tail = self.tail;
|
||||
@ -1377,7 +1379,9 @@ impl<T> VecDeque<T> {
|
||||
/// ```
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn push_back(&mut self, value: T) {
|
||||
self.grow_if_necessary();
|
||||
if self.is_full() {
|
||||
self.grow();
|
||||
}
|
||||
|
||||
let head = self.head;
|
||||
self.head = self.wrap_add(self.head, 1);
|
||||
@ -1485,7 +1489,9 @@ impl<T> VecDeque<T> {
|
||||
#[stable(feature = "deque_extras_15", since = "1.5.0")]
|
||||
pub fn insert(&mut self, index: usize, value: T) {
|
||||
assert!(index <= self.len(), "index out of bounds");
|
||||
self.grow_if_necessary();
|
||||
if self.is_full() {
|
||||
self.grow();
|
||||
}
|
||||
|
||||
// Move the least number of elements in the ring buffer and insert
|
||||
// the given object
|
||||
@ -2003,11 +2009,13 @@ impl<T> VecDeque<T> {
|
||||
}
|
||||
|
||||
// This may panic or abort
|
||||
#[inline]
|
||||
fn grow_if_necessary(&mut self) {
|
||||
#[inline(never)]
|
||||
fn grow(&mut self) {
|
||||
if self.is_full() {
|
||||
let old_cap = self.cap();
|
||||
self.buf.double();
|
||||
// Double the buffer size.
|
||||
self.buf.reserve_exact(old_cap, old_cap);
|
||||
assert!(self.cap() == old_cap * 2);
|
||||
unsafe {
|
||||
self.handle_capacity_increase(old_cap);
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ use super::*;
|
||||
use test;
|
||||
|
||||
#[bench]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
|
||||
#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
|
||||
fn bench_push_back_100(b: &mut test::Bencher) {
|
||||
let mut deq = VecDeque::with_capacity(101);
|
||||
b.iter(|| {
|
||||
@ -16,7 +16,7 @@ fn bench_push_back_100(b: &mut test::Bencher) {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
|
||||
#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
|
||||
fn bench_push_front_100(b: &mut test::Bencher) {
|
||||
let mut deq = VecDeque::with_capacity(101);
|
||||
b.iter(|| {
|
||||
@ -29,7 +29,7 @@ fn bench_push_front_100(b: &mut test::Bencher) {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
|
||||
#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
|
||||
fn bench_pop_back_100(b: &mut test::Bencher) {
|
||||
let mut deq = VecDeque::<i32>::with_capacity(101);
|
||||
|
||||
@ -43,7 +43,7 @@ fn bench_pop_back_100(b: &mut test::Bencher) {
|
||||
}
|
||||
|
||||
#[bench]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support benchmarks
|
||||
#[cfg_attr(miri, ignore)] // isolated Miri does not support benchmarks
|
||||
fn bench_pop_front_100(b: &mut test::Bencher) {
|
||||
let mut deq = VecDeque::<i32>::with_capacity(101);
|
||||
|
||||
|
@ -109,7 +109,7 @@
|
||||
#![feature(ptr_offset_from)]
|
||||
#![feature(rustc_attrs)]
|
||||
#![feature(receiver_trait)]
|
||||
#![feature(specialization)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(std_internals)]
|
||||
#![feature(str_internals)]
|
||||
|
@ -1,7 +1,7 @@
|
||||
#![unstable(feature = "raw_vec_internals", reason = "implementation detail", issue = "none")]
|
||||
#![doc(hidden)]
|
||||
|
||||
use core::alloc::MemoryBlock;
|
||||
use core::alloc::{LayoutErr, MemoryBlock};
|
||||
use core::cmp;
|
||||
use core::mem::{self, ManuallyDrop, MaybeUninit};
|
||||
use core::ops::Drop;
|
||||
@ -211,82 +211,6 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Doubles the size of the type's backing allocation. This is common enough
|
||||
/// to want to do that it's easiest to just have a dedicated method. Slightly
|
||||
/// more efficient logic can be provided for this than the general case.
|
||||
///
|
||||
/// This function is ideal for when pushing elements one-at-a-time because
|
||||
/// you don't need to incur the costs of the more general computations
|
||||
/// reserve needs to do to guard against overflow. You do however need to
|
||||
/// manually check if your `len == capacity`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// * Panics if `T` is zero-sized on the assumption that you managed to exhaust
|
||||
/// all `usize::MAX` slots in your imaginary buffer.
|
||||
/// * Panics on 32-bit platforms if the requested capacity exceeds
|
||||
/// `isize::MAX` bytes.
|
||||
///
|
||||
/// # Aborts
|
||||
///
|
||||
/// Aborts on OOM
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(raw_vec_internals)]
|
||||
/// # extern crate alloc;
|
||||
/// # use std::ptr;
|
||||
/// # use alloc::raw_vec::RawVec;
|
||||
/// struct MyVec<T> {
|
||||
/// buf: RawVec<T>,
|
||||
/// len: usize,
|
||||
/// }
|
||||
///
|
||||
/// impl<T> MyVec<T> {
|
||||
/// pub fn push(&mut self, elem: T) {
|
||||
/// if self.len == self.buf.capacity() { self.buf.double(); }
|
||||
/// // double would have aborted or panicked if the len exceeded
|
||||
/// // `isize::MAX` so this is safe to do unchecked now.
|
||||
/// unsafe {
|
||||
/// ptr::write(self.buf.ptr().add(self.len), elem);
|
||||
/// }
|
||||
/// self.len += 1;
|
||||
/// }
|
||||
/// }
|
||||
/// # fn main() {
|
||||
/// # let mut vec = MyVec { buf: RawVec::new(), len: 0 };
|
||||
/// # vec.push(1);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
pub fn double(&mut self) {
|
||||
match self.grow(Double, MayMove, Uninitialized) {
|
||||
Err(CapacityOverflow) => capacity_overflow(),
|
||||
Err(AllocError { layout, .. }) => handle_alloc_error(layout),
|
||||
Ok(()) => { /* yay */ }
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to double the size of the type's backing allocation in place. This is common
|
||||
/// enough to want to do that it's easiest to just have a dedicated method. Slightly
|
||||
/// more efficient logic can be provided for this than the general case.
|
||||
///
|
||||
/// Returns `true` if the reallocation attempt has succeeded.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// * Panics if `T` is zero-sized on the assumption that you managed to exhaust
|
||||
/// all `usize::MAX` slots in your imaginary buffer.
|
||||
/// * Panics on 32-bit platforms if the requested capacity exceeds
|
||||
/// `isize::MAX` bytes.
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
pub fn double_in_place(&mut self) -> bool {
|
||||
self.grow(Double, InPlace, Uninitialized).is_ok()
|
||||
}
|
||||
|
||||
/// Ensures that the buffer contains at least enough space to hold
|
||||
/// `used_capacity + needed_extra_capacity` elements. If it doesn't already have
|
||||
/// enough capacity, will reallocate enough space plus comfortable slack
|
||||
@ -354,7 +278,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||
needed_extra_capacity: usize,
|
||||
) -> Result<(), TryReserveError> {
|
||||
if self.needs_to_grow(used_capacity, needed_extra_capacity) {
|
||||
self.grow(Amortized { used_capacity, needed_extra_capacity }, MayMove, Uninitialized)
|
||||
self.grow_amortized(used_capacity, needed_extra_capacity, MayMove)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@ -381,8 +305,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||
// This is more readable than putting this in one line:
|
||||
// `!self.needs_to_grow(...) || self.grow(...).is_ok()`
|
||||
if self.needs_to_grow(used_capacity, needed_extra_capacity) {
|
||||
self.grow(Amortized { used_capacity, needed_extra_capacity }, InPlace, Uninitialized)
|
||||
.is_ok()
|
||||
self.grow_amortized(used_capacity, needed_extra_capacity, InPlace).is_ok()
|
||||
} else {
|
||||
true
|
||||
}
|
||||
@ -423,7 +346,7 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||
needed_extra_capacity: usize,
|
||||
) -> Result<(), TryReserveError> {
|
||||
if self.needs_to_grow(used_capacity, needed_extra_capacity) {
|
||||
self.grow(Exact { used_capacity, needed_extra_capacity }, MayMove, Uninitialized)
|
||||
self.grow_exact(used_capacity, needed_extra_capacity)
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
@ -448,14 +371,6 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum Strategy {
|
||||
Double,
|
||||
Amortized { used_capacity: usize, needed_extra_capacity: usize },
|
||||
Exact { used_capacity: usize, needed_extra_capacity: usize },
|
||||
}
|
||||
use Strategy::*;
|
||||
|
||||
impl<T, A: AllocRef> RawVec<T, A> {
|
||||
/// Returns if the buffer needs to grow to fulfill the needed extra capacity.
|
||||
/// Mainly used to make inlining reserve-calls possible without inlining `grow`.
|
||||
@ -473,68 +388,59 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||
self.cap = Self::capacity_from_bytes(memory.size);
|
||||
}
|
||||
|
||||
/// Single method to handle all possibilities of growing the buffer.
|
||||
fn grow(
|
||||
// This method is usually instantiated many times. So we want it to be as
|
||||
// small as possible, to improve compile times. But we also want as much of
|
||||
// its contents to be statically computable as possible, to make the
|
||||
// generated code run faster. Therefore, this method is carefully written
|
||||
// so that all of the code that depends on `T` is within it, while as much
|
||||
// of the code that doesn't depend on `T` as possible is in functions that
|
||||
// are non-generic over `T`.
|
||||
fn grow_amortized(
|
||||
&mut self,
|
||||
strategy: Strategy,
|
||||
used_capacity: usize,
|
||||
needed_extra_capacity: usize,
|
||||
placement: ReallocPlacement,
|
||||
init: AllocInit,
|
||||
) -> Result<(), TryReserveError> {
|
||||
let elem_size = mem::size_of::<T>();
|
||||
if elem_size == 0 {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// Since we return a capacity of `usize::MAX` when `elem_size` is
|
||||
// 0, getting to here necessarily means the `RawVec` is overfull.
|
||||
return Err(CapacityOverflow);
|
||||
}
|
||||
let new_layout = match strategy {
|
||||
Double => unsafe {
|
||||
// Since we guarantee that we never allocate more than `isize::MAX` bytes,
|
||||
// `elem_size * self.cap <= isize::MAX` as a precondition, so this can't overflow.
|
||||
// Additionally the alignment will never be too large as to "not be satisfiable",
|
||||
// so `Layout::from_size_align` will always return `Some`.
|
||||
//
|
||||
// TL;DR, we bypass runtime checks due to dynamic assertions in this module,
|
||||
// allowing us to use `from_size_align_unchecked`.
|
||||
let cap = if self.cap == 0 {
|
||||
// Skip to 4 because tiny `Vec`'s are dumb; but not if that would cause overflow.
|
||||
if elem_size > usize::MAX / 8 { 1 } else { 4 }
|
||||
} else {
|
||||
self.cap * 2
|
||||
};
|
||||
Layout::from_size_align_unchecked(cap * elem_size, mem::align_of::<T>())
|
||||
},
|
||||
Amortized { used_capacity, needed_extra_capacity } => {
|
||||
// Nothing we can really do about these checks, sadly.
|
||||
let required_cap =
|
||||
used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
|
||||
// Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
|
||||
let double_cap = self.cap * 2;
|
||||
// `double_cap` guarantees exponential growth.
|
||||
let cap = cmp::max(double_cap, required_cap);
|
||||
Layout::array::<T>(cap).map_err(|_| CapacityOverflow)?
|
||||
}
|
||||
Exact { used_capacity, needed_extra_capacity } => {
|
||||
let cap =
|
||||
used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
|
||||
Layout::array::<T>(cap).map_err(|_| CapacityOverflow)?
|
||||
}
|
||||
};
|
||||
alloc_guard(new_layout.size())?;
|
||||
|
||||
let memory = if let Some((ptr, old_layout)) = self.current_memory() {
|
||||
debug_assert_eq!(old_layout.align(), new_layout.align());
|
||||
unsafe {
|
||||
self.alloc
|
||||
.grow(ptr, old_layout, new_layout.size(), placement, init)
|
||||
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
|
||||
}
|
||||
} else {
|
||||
match placement {
|
||||
MayMove => self.alloc.alloc(new_layout, init),
|
||||
InPlace => Err(AllocErr),
|
||||
}
|
||||
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?
|
||||
};
|
||||
// Nothing we can really do about these checks, sadly.
|
||||
let required_cap =
|
||||
used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
|
||||
// Cannot overflow, because `cap <= isize::MAX`, and type of `cap` is `usize`.
|
||||
let double_cap = self.cap * 2;
|
||||
// `double_cap` guarantees exponential growth.
|
||||
let cap = cmp::max(double_cap, required_cap);
|
||||
let new_layout = Layout::array::<T>(cap);
|
||||
|
||||
// `finish_grow` is non-generic over `T`.
|
||||
let memory = finish_grow(new_layout, placement, self.current_memory(), &mut self.alloc)?;
|
||||
self.set_memory(memory);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// The constraints on this method are much the same as those on
|
||||
// `grow_amortized`, but this method is usually instantiated less often so
|
||||
// it's less critical.
|
||||
fn grow_exact(
|
||||
&mut self,
|
||||
used_capacity: usize,
|
||||
needed_extra_capacity: usize,
|
||||
) -> Result<(), TryReserveError> {
|
||||
if mem::size_of::<T>() == 0 {
|
||||
// Since we return a capacity of `usize::MAX` when the type size is
|
||||
// 0, getting to here necessarily means the `RawVec` is overfull.
|
||||
return Err(CapacityOverflow);
|
||||
}
|
||||
|
||||
let cap = used_capacity.checked_add(needed_extra_capacity).ok_or(CapacityOverflow)?;
|
||||
let new_layout = Layout::array::<T>(cap);
|
||||
|
||||
// `finish_grow` is non-generic over `T`.
|
||||
let memory = finish_grow(new_layout, MayMove, self.current_memory(), &mut self.alloc)?;
|
||||
self.set_memory(memory);
|
||||
Ok(())
|
||||
}
|
||||
@ -562,6 +468,38 @@ impl<T, A: AllocRef> RawVec<T, A> {
|
||||
}
|
||||
}
|
||||
|
||||
// This function is outside `RawVec` to minimize compile times. See the comment
|
||||
// above `RawVec::grow_amortized` for details. (The `A` parameter isn't
|
||||
// significant, because the number of different `A` types seen in practice is
|
||||
// much smaller than the number of `T` types.)
|
||||
fn finish_grow<A>(
|
||||
new_layout: Result<Layout, LayoutErr>,
|
||||
placement: ReallocPlacement,
|
||||
current_memory: Option<(NonNull<u8>, Layout)>,
|
||||
alloc: &mut A,
|
||||
) -> Result<MemoryBlock, TryReserveError>
|
||||
where
|
||||
A: AllocRef,
|
||||
{
|
||||
// Check for the error here to minimize the size of `RawVec::grow_*`.
|
||||
let new_layout = new_layout.map_err(|_| CapacityOverflow)?;
|
||||
|
||||
alloc_guard(new_layout.size())?;
|
||||
|
||||
let memory = if let Some((ptr, old_layout)) = current_memory {
|
||||
debug_assert_eq!(old_layout.align(), new_layout.align());
|
||||
unsafe { alloc.grow(ptr, old_layout, new_layout.size(), placement, Uninitialized) }
|
||||
} else {
|
||||
match placement {
|
||||
MayMove => alloc.alloc(new_layout, Uninitialized),
|
||||
InPlace => Err(AllocErr),
|
||||
}
|
||||
}
|
||||
.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?;
|
||||
|
||||
Ok(memory)
|
||||
}
|
||||
|
||||
impl<T> RawVec<T, Global> {
|
||||
/// Converts the entire buffer into `Box<[MaybeUninit<T>]>` with the specified `len`.
|
||||
///
|
||||
|
@ -249,7 +249,7 @@ use core::mem::{self, align_of, align_of_val, forget, size_of_val};
|
||||
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
|
||||
use core::pin::Pin;
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::slice::{self, from_raw_parts_mut};
|
||||
use core::slice::from_raw_parts_mut;
|
||||
|
||||
use crate::alloc::{box_free, handle_alloc_error, AllocInit, AllocRef, Global, Layout};
|
||||
use crate::string::String;
|
||||
@ -1221,6 +1221,12 @@ impl<T: ?Sized + PartialEq> RcEqIdent<T> for Rc<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// Hack to allow specializing on `Eq` even though `Eq` has a method.
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
pub(crate) trait MarkerEq: PartialEq<Self> {}
|
||||
|
||||
impl<T: Eq> MarkerEq for T {}
|
||||
|
||||
/// We're doing this specialization here, and not as a more general optimization on `&T`, because it
|
||||
/// would otherwise add a cost to all equality checks on refs. We assume that `Rc`s are used to
|
||||
/// store large values, that are slow to clone, but also heavy to check for equality, causing this
|
||||
@ -1229,7 +1235,7 @@ impl<T: ?Sized + PartialEq> RcEqIdent<T> for Rc<T> {
|
||||
///
|
||||
/// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + Eq> RcEqIdent<T> for Rc<T> {
|
||||
impl<T: ?Sized + MarkerEq> RcEqIdent<T> for Rc<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Rc<T>) -> bool {
|
||||
Rc::ptr_eq(self, other) || **self == **other
|
||||
@ -1548,25 +1554,25 @@ impl<T> iter::FromIterator<T> for Rc<[T]> {
|
||||
/// # assert_eq!(&*evens, &*(0..10).collect::<Vec<_>>());
|
||||
/// ```
|
||||
fn from_iter<I: iter::IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
RcFromIter::from_iter(iter.into_iter())
|
||||
ToRcSlice::to_rc_slice(iter.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
/// Specialization trait used for collecting into `Rc<[T]>`.
|
||||
trait RcFromIter<T, I> {
|
||||
fn from_iter(iter: I) -> Self;
|
||||
trait ToRcSlice<T>: Iterator<Item = T> + Sized {
|
||||
fn to_rc_slice(self) -> Rc<[T]>;
|
||||
}
|
||||
|
||||
impl<T, I: Iterator<Item = T>> RcFromIter<T, I> for Rc<[T]> {
|
||||
default fn from_iter(iter: I) -> Self {
|
||||
iter.collect::<Vec<T>>().into()
|
||||
impl<T, I: Iterator<Item = T>> ToRcSlice<T> for I {
|
||||
default fn to_rc_slice(self) -> Rc<[T]> {
|
||||
self.collect::<Vec<T>>().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I: iter::TrustedLen<Item = T>> RcFromIter<T, I> for Rc<[T]> {
|
||||
default fn from_iter(iter: I) -> Self {
|
||||
impl<T, I: iter::TrustedLen<Item = T>> ToRcSlice<T> for I {
|
||||
fn to_rc_slice(self) -> Rc<[T]> {
|
||||
// This is the case for a `TrustedLen` iterator.
|
||||
let (low, high) = iter.size_hint();
|
||||
let (low, high) = self.size_hint();
|
||||
if let Some(high) = high {
|
||||
debug_assert_eq!(
|
||||
low,
|
||||
@ -1577,29 +1583,15 @@ impl<T, I: iter::TrustedLen<Item = T>> RcFromIter<T, I> for Rc<[T]> {
|
||||
|
||||
unsafe {
|
||||
// SAFETY: We need to ensure that the iterator has an exact length and we have.
|
||||
Rc::from_iter_exact(iter, low)
|
||||
Rc::from_iter_exact(self, low)
|
||||
}
|
||||
} else {
|
||||
// Fall back to normal implementation.
|
||||
iter.collect::<Vec<T>>().into()
|
||||
self.collect::<Vec<T>>().into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + Clone> RcFromIter<&'a T, slice::Iter<'a, T>> for Rc<[T]> {
|
||||
fn from_iter(iter: slice::Iter<'a, T>) -> Self {
|
||||
// Delegate to `impl<T: Clone> From<&[T]> for Rc<[T]>`.
|
||||
//
|
||||
// In the case that `T: Copy`, we get to use `ptr::copy_nonoverlapping`
|
||||
// which is even more performant.
|
||||
//
|
||||
// In the fall-back case we have `T: Clone`. This is still better
|
||||
// than the `TrustedLen` implementation as slices have a known length
|
||||
// and so we get to avoid calling `size_hint` and avoid the branching.
|
||||
iter.as_slice().into()
|
||||
}
|
||||
}
|
||||
|
||||
/// `Weak` is a version of [`Rc`] that holds a non-owning reference to the
|
||||
/// managed allocation. The allocation is accessed by calling [`upgrade`] on the `Weak`
|
||||
/// pointer, which returns an [`Option`]`<`[`Rc`]`<T>>`.
|
||||
@ -2035,6 +2027,8 @@ trait RcBoxPtr<T: ?Sized> {
|
||||
// nevertheless, we insert an abort here to hint LLVM at
|
||||
// an otherwise missed optimization.
|
||||
if strong == 0 || strong == usize::max_value() {
|
||||
// remove `unsafe` on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
@ -2061,6 +2055,8 @@ trait RcBoxPtr<T: ?Sized> {
|
||||
// nevertheless, we insert an abort here to hint LLVM at
|
||||
// an otherwise missed optimization.
|
||||
if weak == 0 || weak == usize::max_value() {
|
||||
// remove `unsafe` on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ use core::mem::{self, align_of, align_of_val, size_of_val};
|
||||
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
|
||||
use core::pin::Pin;
|
||||
use core::ptr::{self, NonNull};
|
||||
use core::slice::{self, from_raw_parts_mut};
|
||||
use core::slice::from_raw_parts_mut;
|
||||
use core::sync::atomic;
|
||||
use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst};
|
||||
|
||||
@ -835,12 +835,14 @@ impl<T: ?Sized> Arc<T> {
|
||||
///
|
||||
/// unsafe {
|
||||
/// let ptr = Arc::into_raw(five);
|
||||
/// Arc::decr_strong_count(ptr);
|
||||
/// Arc::incr_strong_count(ptr);
|
||||
///
|
||||
/// // This assertion is deterministic because we haven't shared
|
||||
/// // Those assertions are deterministic because we haven't shared
|
||||
/// // the `Arc` between threads.
|
||||
/// let five = Arc::from_raw(ptr);
|
||||
/// assert_eq!(0, Arc::strong_count(&five));
|
||||
/// assert_eq!(2, Arc::strong_count(&five));
|
||||
/// Arc::decr_strong_count(ptr);
|
||||
/// assert_eq!(1, Arc::strong_count(&five));
|
||||
/// }
|
||||
/// ```
|
||||
#[inline]
|
||||
@ -1094,6 +1096,8 @@ impl<T: ?Sized> Clone for Arc<T> {
|
||||
// We abort because such a program is incredibly degenerate, and we
|
||||
// don't care to support it.
|
||||
if old_size > MAX_REFCOUNT {
|
||||
// remove `unsafe` on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
@ -1612,6 +1616,8 @@ impl<T: ?Sized> Weak<T> {
|
||||
|
||||
// See comments in `Arc::clone` for why we do this (for `mem::forget`).
|
||||
if n > MAX_REFCOUNT {
|
||||
// remove `unsafe` on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
@ -1751,6 +1757,7 @@ impl<T: ?Sized> Clone for Weak<T> {
|
||||
|
||||
// See comments in Arc::clone() for why we do this (for mem::forget).
|
||||
if old_size > MAX_REFCOUNT {
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
|
||||
unsafe {
|
||||
abort();
|
||||
}
|
||||
@ -1852,7 +1859,7 @@ impl<T: ?Sized + PartialEq> ArcEqIdent<T> for Arc<T> {
|
||||
///
|
||||
/// We can only do this when `T: Eq` as a `PartialEq` might be deliberately irreflexive.
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized + Eq> ArcEqIdent<T> for Arc<T> {
|
||||
impl<T: ?Sized + crate::rc::MarkerEq> ArcEqIdent<T> for Arc<T> {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Arc<T>) -> bool {
|
||||
Arc::ptr_eq(self, other) || **self == **other
|
||||
@ -2178,25 +2185,25 @@ impl<T> iter::FromIterator<T> for Arc<[T]> {
|
||||
/// # assert_eq!(&*evens, &*(0..10).collect::<Vec<_>>());
|
||||
/// ```
|
||||
fn from_iter<I: iter::IntoIterator<Item = T>>(iter: I) -> Self {
|
||||
ArcFromIter::from_iter(iter.into_iter())
|
||||
ToArcSlice::to_arc_slice(iter.into_iter())
|
||||
}
|
||||
}
|
||||
|
||||
/// Specialization trait used for collecting into `Arc<[T]>`.
|
||||
trait ArcFromIter<T, I> {
|
||||
fn from_iter(iter: I) -> Self;
|
||||
trait ToArcSlice<T>: Iterator<Item = T> + Sized {
|
||||
fn to_arc_slice(self) -> Arc<[T]>;
|
||||
}
|
||||
|
||||
impl<T, I: Iterator<Item = T>> ArcFromIter<T, I> for Arc<[T]> {
|
||||
default fn from_iter(iter: I) -> Self {
|
||||
iter.collect::<Vec<T>>().into()
|
||||
impl<T, I: Iterator<Item = T>> ToArcSlice<T> for I {
|
||||
default fn to_arc_slice(self) -> Arc<[T]> {
|
||||
self.collect::<Vec<T>>().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, I: iter::TrustedLen<Item = T>> ArcFromIter<T, I> for Arc<[T]> {
|
||||
default fn from_iter(iter: I) -> Self {
|
||||
impl<T, I: iter::TrustedLen<Item = T>> ToArcSlice<T> for I {
|
||||
fn to_arc_slice(self) -> Arc<[T]> {
|
||||
// This is the case for a `TrustedLen` iterator.
|
||||
let (low, high) = iter.size_hint();
|
||||
let (low, high) = self.size_hint();
|
||||
if let Some(high) = high {
|
||||
debug_assert_eq!(
|
||||
low,
|
||||
@ -2207,29 +2214,15 @@ impl<T, I: iter::TrustedLen<Item = T>> ArcFromIter<T, I> for Arc<[T]> {
|
||||
|
||||
unsafe {
|
||||
// SAFETY: We need to ensure that the iterator has an exact length and we have.
|
||||
Arc::from_iter_exact(iter, low)
|
||||
Arc::from_iter_exact(self, low)
|
||||
}
|
||||
} else {
|
||||
// Fall back to normal implementation.
|
||||
iter.collect::<Vec<T>>().into()
|
||||
self.collect::<Vec<T>>().into()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: 'a + Clone> ArcFromIter<&'a T, slice::Iter<'a, T>> for Arc<[T]> {
|
||||
fn from_iter(iter: slice::Iter<'a, T>) -> Self {
|
||||
// Delegate to `impl<T: Clone> From<&[T]> for Arc<[T]>`.
|
||||
//
|
||||
// In the case that `T: Copy`, we get to use `ptr::copy_nonoverlapping`
|
||||
// which is even more performant.
|
||||
//
|
||||
// In the fall-back case we have `T: Clone`. This is still better
|
||||
// than the `TrustedLen` implementation as slices have a known length
|
||||
// and so we get to avoid calling `size_hint` and avoid the branching.
|
||||
iter.as_slice().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<T: ?Sized> borrow::Borrow<T> for Arc<T> {
|
||||
fn borrow(&self) -> &T {
|
||||
|
@ -32,7 +32,6 @@ impl Drop for Canary {
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support threads
|
||||
fn manually_share_arc() {
|
||||
let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
let arc_v = Arc::new(v);
|
||||
@ -337,12 +336,13 @@ fn test_ptr_eq() {
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(target_os = "emscripten", ignore)]
|
||||
#[cfg_attr(miri, ignore)] // Miri does not support threads
|
||||
fn test_weak_count_locked() {
|
||||
let mut a = Arc::new(atomic::AtomicBool::new(false));
|
||||
let a2 = a.clone();
|
||||
let t = thread::spawn(move || {
|
||||
for _i in 0..1000000 {
|
||||
// Miri is too slow
|
||||
let count = if cfg!(miri) { 1000 } else { 1000000 };
|
||||
for _i in 0..count {
|
||||
Arc::get_mut(&mut a);
|
||||
}
|
||||
a.store(true, SeqCst);
|
||||
@ -351,6 +351,8 @@ fn test_weak_count_locked() {
|
||||
while !a2.load(SeqCst) {
|
||||
let n = Arc::weak_count(&a2);
|
||||
assert!(n < 2, "bad weak count: {}", n);
|
||||
#[cfg(miri)] // Miri's scheduler does not guarantee liveness, and thus needs this hint.
|
||||
atomic::spin_loop_hint();
|
||||
}
|
||||
t.join().unwrap();
|
||||
}
|
||||
|
@ -1619,8 +1619,8 @@ impl<T: Default> Vec<T> {
|
||||
#[unstable(feature = "vec_resize_default", issue = "41758")]
|
||||
#[rustc_deprecated(
|
||||
reason = "This is moving towards being removed in favor \
|
||||
of `.resize_with(Default::default)`. If you disagree, please comment \
|
||||
in the tracking issue.",
|
||||
of `.resize_with(Default::default)`. If you disagree, please comment \
|
||||
in the tracking issue.",
|
||||
since = "1.33.0"
|
||||
)]
|
||||
pub fn resize_default(&mut self, new_len: usize) {
|
||||
@ -1825,6 +1825,7 @@ impl<T: Clone + IsZero> SpecFromElem for T {
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_specialization_trait]
|
||||
unsafe trait IsZero {
|
||||
/// Whether this value is zero
|
||||
fn is_zero(&self) -> bool;
|
||||
@ -1874,9 +1875,12 @@ unsafe impl<T> IsZero for *mut T {
|
||||
}
|
||||
}
|
||||
|
||||
// `Option<&T>`, `Option<&mut T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
|
||||
// For fat pointers, the bytes that would be the pointer metadata in the `Some` variant
|
||||
// are padding in the `None` variant, so ignoring them and zero-initializing instead is ok.
|
||||
// `Option<&T>` and `Option<Box<T>>` are guaranteed to represent `None` as null.
|
||||
// For fat pointers, the bytes that would be the pointer metadata in the `Some`
|
||||
// variant are padding in the `None` variant, so ignoring them and
|
||||
// zero-initializing instead is ok.
|
||||
// `Option<&mut T>` never implements `Clone`, so there's no need for an impl of
|
||||
// `SpecFromElem`.
|
||||
|
||||
unsafe impl<T: ?Sized> IsZero for Option<&T> {
|
||||
#[inline]
|
||||
@ -1885,13 +1889,6 @@ unsafe impl<T: ?Sized> IsZero for Option<&T> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized> IsZero for Option<&mut T> {
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
self.is_none()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ?Sized> IsZero for Option<Box<T>> {
|
||||
#[inline]
|
||||
fn is_zero(&self) -> bool {
|
||||
|
@ -5,8 +5,7 @@
|
||||
//! of individual objects while the arena itself is still alive. The benefit
|
||||
//! of an arena is very fast allocation; just a pointer bump.
|
||||
//!
|
||||
//! This crate implements `TypedArena`, a simple arena that can only hold
|
||||
//! objects of a single type.
|
||||
//! This crate implements several kinds of arena.
|
||||
|
||||
#![doc(
|
||||
html_root_url = "https://doc.rust-lang.org/nightly/",
|
||||
@ -98,7 +97,13 @@ impl<T> TypedArenaChunk<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// The arenas start with PAGE-sized chunks, and then each new chunk is twice as
|
||||
// big as its predecessor, up until we reach HUGE_PAGE-sized chunks, whereupon
|
||||
// we stop growing. This scales well, from arenas that are barely used up to
|
||||
// arenas that are used for 100s of MiBs. Note also that the chosen sizes match
|
||||
// the usual sizes of pages and huge pages on Linux.
|
||||
const PAGE: usize = 4096;
|
||||
const HUGE_PAGE: usize = 2 * 1024 * 1024;
|
||||
|
||||
impl<T> Default for TypedArena<T> {
|
||||
/// Creates a new `TypedArena`.
|
||||
@ -211,6 +216,9 @@ impl<T> TypedArena<T> {
|
||||
#[cold]
|
||||
fn grow(&self, n: usize) {
|
||||
unsafe {
|
||||
// We need the element size in to convert chunk sizes (ranging from
|
||||
// PAGE to HUGE_PAGE bytes) to element counts.
|
||||
let elem_size = cmp::max(1, mem::size_of::<T>());
|
||||
let mut chunks = self.chunks.borrow_mut();
|
||||
let (chunk, mut new_capacity);
|
||||
if let Some(last_chunk) = chunks.last_mut() {
|
||||
@ -221,18 +229,20 @@ impl<T> TypedArena<T> {
|
||||
self.end.set(last_chunk.end());
|
||||
return;
|
||||
} else {
|
||||
// If the previous chunk's capacity is less than HUGE_PAGE
|
||||
// bytes, then this chunk will be least double the previous
|
||||
// chunk's size.
|
||||
new_capacity = last_chunk.storage.capacity();
|
||||
loop {
|
||||
if new_capacity < HUGE_PAGE / elem_size {
|
||||
new_capacity = new_capacity.checked_mul(2).unwrap();
|
||||
if new_capacity >= currently_used_cap + n {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let elem_size = cmp::max(1, mem::size_of::<T>());
|
||||
new_capacity = cmp::max(n, PAGE / elem_size);
|
||||
new_capacity = PAGE / elem_size;
|
||||
}
|
||||
// Also ensure that this chunk can fit `n`.
|
||||
new_capacity = cmp::max(n, new_capacity);
|
||||
|
||||
chunk = TypedArenaChunk::<T>::new(new_capacity);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
@ -347,17 +357,20 @@ impl DroplessArena {
|
||||
self.end.set(last_chunk.end());
|
||||
return;
|
||||
} else {
|
||||
// If the previous chunk's capacity is less than HUGE_PAGE
|
||||
// bytes, then this chunk will be least double the previous
|
||||
// chunk's size.
|
||||
new_capacity = last_chunk.storage.capacity();
|
||||
loop {
|
||||
if new_capacity < HUGE_PAGE {
|
||||
new_capacity = new_capacity.checked_mul(2).unwrap();
|
||||
if new_capacity >= used_bytes + needed_bytes {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
new_capacity = cmp::max(needed_bytes, PAGE);
|
||||
new_capacity = PAGE;
|
||||
}
|
||||
// Also ensure that this chunk can fit `needed_bytes`.
|
||||
new_capacity = cmp::max(needed_bytes, new_capacity);
|
||||
|
||||
chunk = TypedArenaChunk::<u8>::new(new_capacity);
|
||||
self.ptr.set(chunk.start());
|
||||
self.end.set(chunk.end());
|
||||
|
@ -446,14 +446,16 @@ impl TypeId {
|
||||
/// # Note
|
||||
///
|
||||
/// This is intended for diagnostic use. The exact contents and format of the
|
||||
/// string are not specified, other than being a best-effort description of the
|
||||
/// type. For example, `type_name::<Option<String>>()` could return the
|
||||
/// `"Option<String>"` or `"std::option::Option<std::string::String>"`, but not
|
||||
/// `"foobar"`. In addition, the output may change between versions of the
|
||||
/// compiler.
|
||||
/// string returned are not specified, other than being a best-effort
|
||||
/// description of the type. For example, amongst the strings
|
||||
/// that `type_name::<Option<String>>()` might return are `"Option<String>"` and
|
||||
/// `"std::option::Option<std::string::String>"`.
|
||||
///
|
||||
/// The type name should not be considered a unique identifier of a type;
|
||||
/// multiple types may share the same type name.
|
||||
/// The returned string must not be considered to be a unique identifier of a
|
||||
/// type as multiple types may map to the same type name. Similarly, there is no
|
||||
/// guarantee that all parts of a type will appear in the returned string: for
|
||||
/// example, lifetime specifiers are currently not included. In addition, the
|
||||
/// output may change between versions of the compiler.
|
||||
///
|
||||
/// The current implementation uses the same infrastructure as compiler
|
||||
/// diagnostics and debuginfo, but this is not guaranteed.
|
||||
|
@ -133,10 +133,9 @@
|
||||
//! `Cell<T>`.
|
||||
//!
|
||||
//! ```
|
||||
//! #![feature(core_intrinsics)]
|
||||
//! use std::cell::Cell;
|
||||
//! use std::ptr::NonNull;
|
||||
//! use std::intrinsics::abort;
|
||||
//! use std::process::abort;
|
||||
//! use std::marker::PhantomData;
|
||||
//!
|
||||
//! struct Rc<T: ?Sized> {
|
||||
@ -173,7 +172,7 @@
|
||||
//! .strong
|
||||
//! .set(self.strong()
|
||||
//! .checked_add(1)
|
||||
//! .unwrap_or_else(|| unsafe { abort() }));
|
||||
//! .unwrap_or_else(|| abort() ));
|
||||
//! }
|
||||
//! }
|
||||
//!
|
||||
|
@ -918,7 +918,7 @@ extern "rust-intrinsic" {
|
||||
|
||||
/// Aborts the execution of the process.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// A more user-friendly and stable version of this operation is
|
||||
/// [`std::process::abort`](../../std/process/fn.abort.html).
|
||||
pub fn abort() -> !;
|
||||
|
||||
|
@ -4,47 +4,182 @@ use crate::ops::{self, Add, Sub, Try};
|
||||
|
||||
use super::{FusedIterator, TrustedLen};
|
||||
|
||||
/// Objects that can be stepped over in both directions.
|
||||
/// Objects that have a notion of *successor* and *predecessor* operations.
|
||||
///
|
||||
/// The `steps_between` function provides a way to efficiently compare
|
||||
/// two `Step` objects.
|
||||
#[unstable(
|
||||
feature = "step_trait",
|
||||
reason = "likely to be replaced by finer-grained traits",
|
||||
issue = "42168"
|
||||
)]
|
||||
pub trait Step: Clone + PartialOrd + Sized {
|
||||
/// Returns the number of steps between two step objects. The count is
|
||||
/// inclusive of `start` and exclusive of `end`.
|
||||
/// The *successor* operation moves towards values that compare greater.
|
||||
/// The *predecessor* operation moves towards values that compare lesser.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This trait is `unsafe` because its implementation must be correct for
|
||||
/// the safety of `unsafe trait TrustedLen` implementations, and the results
|
||||
/// of using this trait can otherwise be trusted by `unsafe` code to be correct
|
||||
/// and fulfill the listed obligations.
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
pub unsafe trait Step: Clone + PartialOrd + Sized {
|
||||
/// Returns the number of *successor* steps required to get from `start` to `end`.
|
||||
///
|
||||
/// Returns `None` if it is not possible to calculate `steps_between`
|
||||
/// without overflow.
|
||||
/// Returns `None` if the number of steps would overflow `usize`
|
||||
/// (or is infinite, or if `end` would never be reached).
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// For any `a`, `b`, and `n`:
|
||||
///
|
||||
/// * `steps_between(&a, &b) == Some(n)` if and only if `Step::forward_checked(&a, n) == Some(b)`
|
||||
/// * `steps_between(&a, &b) == Some(n)` if and only if `Step::backward_checked(&a, n) == Some(a)`
|
||||
/// * `steps_between(&a, &b) == Some(n)` only if `a <= b`
|
||||
/// * Corollary: `steps_between(&a, &b) == Some(0)` if and only if `a == b`
|
||||
/// * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`;
|
||||
/// this is the case wheen it would require more than `usize::MAX` steps to get to `b`
|
||||
/// * `steps_between(&a, &b) == None` if `a > b`
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize>;
|
||||
|
||||
/// Replaces this step with `1`, returning a clone of itself.
|
||||
/// Returns the value that would be obtained by taking the *successor*
|
||||
/// of `self` `count` times.
|
||||
///
|
||||
/// The output of this method should always be greater than the output of replace_zero.
|
||||
fn replace_one(&mut self) -> Self;
|
||||
|
||||
/// Replaces this step with `0`, returning a clone of itself.
|
||||
/// If this would overflow the range of values supported by `Self`, returns `None`.
|
||||
///
|
||||
/// The output of this method should always be less than the output of replace_one.
|
||||
fn replace_zero(&mut self) -> Self;
|
||||
/// # Invariants
|
||||
///
|
||||
/// For any `a`, `n`, and `m`:
|
||||
///
|
||||
/// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, m).and_then(|x| Step::forward_checked(x, n))`
|
||||
///
|
||||
/// For any `a`, `n`, and `m` where `n + m` does not overflow:
|
||||
///
|
||||
/// * `Step::forward_checked(a, n).and_then(|x| Step::forward_checked(x, m)) == Step::forward_checked(a, n + m)`
|
||||
///
|
||||
/// For any `a` and `n`:
|
||||
///
|
||||
/// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))`
|
||||
/// * Corollary: `Step::forward_checked(&a, 0) == Some(a)`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
fn forward_checked(start: Self, count: usize) -> Option<Self>;
|
||||
|
||||
/// Adds one to this step, returning the result.
|
||||
fn add_one(&self) -> Self;
|
||||
/// Returns the value that would be obtained by taking the *successor*
|
||||
/// of `self` `count` times.
|
||||
///
|
||||
/// If this would overflow the range of values supported by `Self`,
|
||||
/// this function is allowed to panic, wrap, or saturate.
|
||||
/// The suggested behavior is to panic when debug assertions are enabled,
|
||||
/// and to wrap or saturate otherwise.
|
||||
///
|
||||
/// Unsafe code should not rely on the correctness of behavior after overflow.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// For any `a`, `n`, and `m`, where no overflow occurs:
|
||||
///
|
||||
/// * `Step::forward(Step::forward(a, n), m) == Step::forward(a, n + m)`
|
||||
///
|
||||
/// For any `a` and `n`, where no overflow occurs:
|
||||
///
|
||||
/// * `Step::forward_checked(a, n) == Some(Step::forward(a, n))`
|
||||
/// * `Step::forward(a, n) == (0..n).fold(a, |x, _| Step::forward(x, 1))`
|
||||
/// * Corollary: `Step::forward(a, 0) == a`
|
||||
/// * `Step::forward(a, n) >= a`
|
||||
/// * `Step::backward(Step::forward(a, n), n) == a`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
fn forward(start: Self, count: usize) -> Self {
|
||||
Step::forward_checked(start, count).expect("overflow in `Step::forward`")
|
||||
}
|
||||
|
||||
/// Subtracts one to this step, returning the result.
|
||||
fn sub_one(&self) -> Self;
|
||||
/// Returns the value that would be obtained by taking the *successor*
|
||||
/// of `self` `count` times.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is undefined behavior for this operation to overflow the
|
||||
/// range of values supported by `Self`. If you cannot guarantee that this
|
||||
/// will not overflow, use `forward` or `forward_checked` instead.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// For any `a`:
|
||||
///
|
||||
/// * if there exists `b` such that `b > a`, it is safe to call `Step::forward_unchecked(a, 1)`
|
||||
/// * if there exists `b`, `n` such that `steps_between(&a, &b) == Some(n)`,
|
||||
/// it is safe to call `Step::forward_unchecked(a, m)` for any `m <= n`.
|
||||
///
|
||||
/// For any `a` and `n`, where no overflow occurs:
|
||||
///
|
||||
/// * `Step::forward_unchecked(a, n)` is equivalent to `Step::forward(a, n)`
|
||||
#[unstable(feature = "unchecked_math", reason = "niche optimization path", issue = "none")]
|
||||
unsafe fn forward_unchecked(start: Self, count: usize) -> Self {
|
||||
Step::forward(start, count)
|
||||
}
|
||||
|
||||
/// Adds a `usize`, returning `None` on overflow.
|
||||
fn add_usize(&self, n: usize) -> Option<Self>;
|
||||
/// Returns the value that would be obtained by taking the *successor*
|
||||
/// of `self` `count` times.
|
||||
///
|
||||
/// If this would overflow the range of values supported by `Self`, returns `None`.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// For any `a`, `n`, and `m`:
|
||||
///
|
||||
/// * `Step::backward_checked(a, n).and_then(|x| Step::backward_checked(x, m)) == n.checked_add(m).and_then(|x| Step::backward_checked(a, x))`
|
||||
/// * `Step::backward_checked(a, n).and_then(|x| Step::backward_checked(x, m)) == try { Step::backward_checked(a, n.checked_add(m)?) }`
|
||||
///
|
||||
/// For any `a` and `n`:
|
||||
///
|
||||
/// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))`
|
||||
/// * Corollary: `Step::backward_checked(&a, 0) == Some(a)`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
fn backward_checked(start: Self, count: usize) -> Option<Self>;
|
||||
|
||||
/// Subtracts a `usize`, returning `None` on underflow.
|
||||
fn sub_usize(&self, n: usize) -> Option<Self> {
|
||||
// this default implementation makes the addition of `sub_usize` a non-breaking change
|
||||
let _ = n;
|
||||
unimplemented!()
|
||||
/// Returns the value that would be obtained by taking the *predecessor*
|
||||
/// of `self` `count` times.
|
||||
///
|
||||
/// If this would overflow the range of values supported by `Self`,
|
||||
/// this function is allowed to panic, wrap, or saturate.
|
||||
/// The suggested behavior is to panic when debug assertions are enabled,
|
||||
/// and to wrap or saturate otherwise.
|
||||
///
|
||||
/// Unsafe code should not rely on the correctness of behavior after overflow.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// For any `a`, `n`, and `m`, where no overflow occurs:
|
||||
///
|
||||
/// * `Step::backward(Step::backward(a, n), m) == Step::backward(a, n + m)`
|
||||
///
|
||||
/// For any `a` and `n`, where no overflow occurs:
|
||||
///
|
||||
/// * `Step::backward_checked(a, n) == Some(Step::backward(a, n))`
|
||||
/// * `Step::backward(a, n) == (0..n).fold(a, |x, _| Step::backward(x, 1))`
|
||||
/// * Corollary: `Step::backward(a, 0) == a`
|
||||
/// * `Step::backward(a, n) <= a`
|
||||
/// * `Step::forward(Step::backward(a, n), n) == a`
|
||||
#[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")]
|
||||
fn backward(start: Self, count: usize) -> Self {
|
||||
Step::backward_checked(start, count).expect("overflow in `Step::backward`")
|
||||
}
|
||||
|
||||
/// Returns the value that would be obtained by taking the *predecessor*
|
||||
/// of `self` `count` times.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is undefined behavior for this operation to overflow the
|
||||
/// range of values supported by `Self`. If you cannot guarantee that this
|
||||
/// will not overflow, use `backward` or `backward_checked` instead.
|
||||
///
|
||||
/// # Invariants
|
||||
///
|
||||
/// For any `a`:
|
||||
///
|
||||
/// * if there exists `b` such that `b < a`, it is safe to call `Step::backward_unchecked(a, 1)`
|
||||
/// * if there exists `b`, `n` such that `steps_between(&b, &a) == Some(n)`,
|
||||
/// it is safe to call `Step::backward_unchecked(a, m)` for any `m <= n`.
|
||||
///
|
||||
/// For any `a` and `n`, where no overflow occurs:
|
||||
///
|
||||
/// * `Step::backward_unchecked(a, n)` is equivalent to `Step::backward(a, n)`
|
||||
#[unstable(feature = "unchecked_math", reason = "niche optimization path", issue = "none")]
|
||||
unsafe fn backward_unchecked(start: Self, count: usize) -> Self {
|
||||
Step::backward(start, count)
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,127 +187,218 @@ pub trait Step: Clone + PartialOrd + Sized {
|
||||
macro_rules! step_identical_methods {
|
||||
() => {
|
||||
#[inline]
|
||||
fn replace_one(&mut self) -> Self {
|
||||
mem::replace(self, 1)
|
||||
unsafe fn forward_unchecked(start: Self, n: usize) -> Self {
|
||||
start.unchecked_add(n as Self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn replace_zero(&mut self) -> Self {
|
||||
mem::replace(self, 0)
|
||||
unsafe fn backward_unchecked(start: Self, n: usize) -> Self {
|
||||
start.unchecked_sub(n as Self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_one(&self) -> Self {
|
||||
Add::add(*self, 1)
|
||||
fn forward(start: Self, n: usize) -> Self {
|
||||
// In debug builds, trigger a panic on overflow.
|
||||
// This should optimize completely out in release builds.
|
||||
if Self::forward_checked(start, n).is_none() {
|
||||
let _ = Add::add(Self::MAX, 1);
|
||||
}
|
||||
// Do wrapping math to allow e.g. `Step::forward(-128i8, 255)`.
|
||||
start.wrapping_add(n as Self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sub_one(&self) -> Self {
|
||||
Sub::sub(*self, 1)
|
||||
fn backward(start: Self, n: usize) -> Self {
|
||||
// In debug builds, trigger a panic on overflow.
|
||||
// This should optimize completely out in release builds.
|
||||
if Self::backward_checked(start, n).is_none() {
|
||||
let _ = Sub::sub(Self::MIN, 1);
|
||||
}
|
||||
// Do wrapping math to allow e.g. `Step::backward(127i8, 255)`.
|
||||
start.wrapping_sub(n as Self)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! step_impl_unsigned {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "step_trait",
|
||||
reason = "likely to be replaced by finer-grained traits",
|
||||
issue = "42168")]
|
||||
impl Step for $t {
|
||||
#[inline]
|
||||
fn steps_between(start: &$t, end: &$t) -> Option<usize> {
|
||||
if *start < *end {
|
||||
usize::try_from(*end - *start).ok()
|
||||
} else {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
macro_rules! step_integer_impls {
|
||||
{
|
||||
narrower than or same width as usize:
|
||||
$( [ $u_narrower:ident $i_narrower:ident ] ),+;
|
||||
wider than usize:
|
||||
$( [ $u_wider:ident $i_wider:ident ] ),+;
|
||||
} => {
|
||||
$(
|
||||
#[allow(unreachable_patterns)]
|
||||
fn add_usize(&self, n: usize) -> Option<Self> {
|
||||
match <$t>::try_from(n) {
|
||||
Ok(n_as_t) => self.checked_add(n_as_t),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for $u_narrower {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
#[allow(unreachable_patterns)]
|
||||
fn sub_usize(&self, n: usize) -> Option<Self> {
|
||||
match <$t>::try_from(n) {
|
||||
Ok(n_as_t) => self.checked_sub(n_as_t),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
step_identical_methods!();
|
||||
}
|
||||
)*)
|
||||
}
|
||||
macro_rules! step_impl_signed {
|
||||
($( [$t:ty : $unsigned:ty] )*) => ($(
|
||||
#[unstable(feature = "step_trait",
|
||||
reason = "likely to be replaced by finer-grained traits",
|
||||
issue = "42168")]
|
||||
impl Step for $t {
|
||||
#[inline]
|
||||
fn steps_between(start: &$t, end: &$t) -> Option<usize> {
|
||||
if *start < *end {
|
||||
// Use .wrapping_sub and cast to unsigned to compute the
|
||||
// difference that may not fit inside the range of $t.
|
||||
usize::try_from(end.wrapping_sub(*start) as $unsigned).ok()
|
||||
} else {
|
||||
Some(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unreachable_patterns)]
|
||||
fn add_usize(&self, n: usize) -> Option<Self> {
|
||||
match <$unsigned>::try_from(n) {
|
||||
Ok(n_as_unsigned) => {
|
||||
// Wrapping in unsigned space handles cases like
|
||||
// `-120_i8.add_usize(200) == Some(80_i8)`,
|
||||
// even though 200_usize is out of range for i8.
|
||||
let wrapped = (*self as $unsigned).wrapping_add(n_as_unsigned) as $t;
|
||||
if wrapped >= *self {
|
||||
Some(wrapped)
|
||||
} else {
|
||||
None // Addition overflowed
|
||||
}
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
||||
if *start <= *end {
|
||||
// This relies on $u_narrower <= usize
|
||||
Some((*end - *start) as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[allow(unreachable_patterns)]
|
||||
fn sub_usize(&self, n: usize) -> Option<Self> {
|
||||
match <$unsigned>::try_from(n) {
|
||||
Ok(n_as_unsigned) => {
|
||||
// Wrapping in unsigned space handles cases like
|
||||
// `80_i8.sub_usize(200) == Some(-120_i8)`,
|
||||
// even though 200_usize is out of range for i8.
|
||||
let wrapped = (*self as $unsigned).wrapping_sub(n_as_unsigned) as $t;
|
||||
if wrapped <= *self {
|
||||
Some(wrapped)
|
||||
} else {
|
||||
None // Subtraction underflowed
|
||||
}
|
||||
#[inline]
|
||||
fn forward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
match Self::try_from(n) {
|
||||
Ok(n) => start.checked_add(n),
|
||||
Err(_) => None, // if n is out of range, `unsigned_start + n` is too
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn backward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
match Self::try_from(n) {
|
||||
Ok(n) => start.checked_sub(n),
|
||||
Err(_) => None, // if n is out of range, `unsigned_start - n` is too
|
||||
}
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
step_identical_methods!();
|
||||
}
|
||||
)*)
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for $i_narrower {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
||||
if *start <= *end {
|
||||
// This relies on $i_narrower <= usize
|
||||
//
|
||||
// Casting to isize extends the width but preserves the sign.
|
||||
// Use wrapping_sub in isize space and cast to usize to compute
|
||||
// the difference that may not fit inside the range of isize.
|
||||
Some((*end as isize).wrapping_sub(*start as isize) as usize)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn forward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
match $u_narrower::try_from(n) {
|
||||
Ok(n) => {
|
||||
// Wrapping handles cases like
|
||||
// `Step::forward(-120_i8, 200) == Some(80_i8)`,
|
||||
// even though 200 is out of range for i8.
|
||||
let wrapped = start.wrapping_add(n as Self);
|
||||
if wrapped >= start {
|
||||
Some(wrapped)
|
||||
} else {
|
||||
None // Addition overflowed
|
||||
}
|
||||
}
|
||||
// If n is out of range of e.g. u8,
|
||||
// then it is bigger than the entire range for i8 is wide
|
||||
// so `any_i8 + n` necessarily overflows i8.
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn backward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
match $u_narrower::try_from(n) {
|
||||
Ok(n) => {
|
||||
// Wrapping handles cases like
|
||||
// `Step::forward(-120_i8, 200) == Some(80_i8)`,
|
||||
// even though 200 is out of range for i8.
|
||||
let wrapped = start.wrapping_sub(n as Self);
|
||||
if wrapped <= start {
|
||||
Some(wrapped)
|
||||
} else {
|
||||
None // Subtraction overflowed
|
||||
}
|
||||
}
|
||||
// If n is out of range of e.g. u8,
|
||||
// then it is bigger than the entire range for i8 is wide
|
||||
// so `any_i8 - n` necessarily overflows i8.
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
)+
|
||||
|
||||
$(
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for $u_wider {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
||||
if *start <= *end {
|
||||
usize::try_from(*end - *start).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn forward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
start.checked_add(n as Self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn backward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
start.checked_sub(n as Self)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unreachable_patterns)]
|
||||
#[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")]
|
||||
unsafe impl Step for $i_wider {
|
||||
step_identical_methods!();
|
||||
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
||||
if *start <= *end {
|
||||
match end.checked_sub(*start) {
|
||||
Some(result) => usize::try_from(result).ok(),
|
||||
// If the difference is too big for e.g. i128,
|
||||
// it's also gonna be too big for usize with fewer bits.
|
||||
None => None,
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn forward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
start.checked_add(n as Self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn backward_checked(start: Self, n: usize) -> Option<Self> {
|
||||
start.checked_sub(n as Self)
|
||||
}
|
||||
}
|
||||
)+
|
||||
};
|
||||
}
|
||||
|
||||
step_impl_unsigned!(usize u8 u16 u32 u64 u128);
|
||||
step_impl_signed!([isize: usize][i8: u8][i16: u16]);
|
||||
step_impl_signed!([i32: u32][i64: u64][i128: u128]);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
step_integer_impls! {
|
||||
narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [u64 i64], [usize isize];
|
||||
wider than usize: [u128 i128];
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
step_integer_impls! {
|
||||
narrower than or same width as usize: [u8 i8], [u16 i16], [u32 i32], [usize isize];
|
||||
wider than usize: [u64 i64], [u128 i128];
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "16")]
|
||||
step_integer_impls! {
|
||||
narrower than or same width as usize: [u8 i8], [u16 i16], [usize isize];
|
||||
wider than usize: [u32 i32], [u64 i64], [u128 i128];
|
||||
}
|
||||
|
||||
macro_rules! range_exact_iter_impl {
|
||||
($($t:ty)*) => ($(
|
||||
@ -188,20 +414,6 @@ macro_rules! range_incl_exact_iter_impl {
|
||||
)*)
|
||||
}
|
||||
|
||||
macro_rules! range_trusted_len_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl TrustedLen for ops::Range<$t> { }
|
||||
)*)
|
||||
}
|
||||
|
||||
macro_rules! range_incl_trusted_len_impl {
|
||||
($($t:ty)*) => ($(
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl TrustedLen for ops::RangeInclusive<$t> { }
|
||||
)*)
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step> Iterator for ops::Range<A> {
|
||||
type Item = A;
|
||||
@ -209,16 +421,12 @@ impl<A: Step> Iterator for ops::Range<A> {
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
if self.start < self.end {
|
||||
// We check for overflow here, even though it can't actually
|
||||
// happen. Adding this check does however help llvm vectorize loops
|
||||
// for some ranges that don't get vectorized otherwise,
|
||||
// and this won't actually result in an extra check in an optimized build.
|
||||
if let Some(mut n) = self.start.add_usize(1) {
|
||||
mem::swap(&mut n, &mut self.start);
|
||||
Some(n)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
// SAFETY: just checked precondition
|
||||
// We use the unchecked version here, because
|
||||
// this helps LLVM vectorize loops for some ranges
|
||||
// that don't get vectorized otherwise.
|
||||
let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) };
|
||||
Some(mem::replace(&mut self.start, n))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -226,17 +434,19 @@ impl<A: Step> Iterator for ops::Range<A> {
|
||||
|
||||
#[inline]
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
match Step::steps_between(&self.start, &self.end) {
|
||||
Some(hint) => (hint, Some(hint)),
|
||||
None => (usize::MAX, None),
|
||||
if self.start < self.end {
|
||||
let hint = Step::steps_between(&self.start, &self.end);
|
||||
(hint.unwrap_or(usize::MAX), hint)
|
||||
} else {
|
||||
(0, Some(0))
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, n: usize) -> Option<A> {
|
||||
if let Some(plus_n) = self.start.add_usize(n) {
|
||||
if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
|
||||
if plus_n < self.end {
|
||||
self.start = plus_n.add_one();
|
||||
self.start = Step::forward(plus_n.clone(), 1);
|
||||
return Some(plus_n);
|
||||
}
|
||||
}
|
||||
@ -262,25 +472,42 @@ impl<A: Step> Iterator for ops::Range<A> {
|
||||
}
|
||||
|
||||
// These macros generate `ExactSizeIterator` impls for various range types.
|
||||
// Range<{u,i}64> and RangeInclusive<{u,i}{32,64,size}> are excluded
|
||||
// because they cannot guarantee having a length <= usize::MAX, which is
|
||||
// required by ExactSizeIterator.
|
||||
range_exact_iter_impl!(usize u8 u16 u32 isize i8 i16 i32);
|
||||
range_incl_exact_iter_impl!(u8 u16 i8 i16);
|
||||
|
||||
// These macros generate `TrustedLen` impls.
|
||||
//
|
||||
// They need to guarantee that .size_hint() is either exact, or that
|
||||
// the upper bound is None when it does not fit the type limits.
|
||||
range_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128);
|
||||
range_incl_trusted_len_impl!(usize isize u8 i8 u16 i16 u32 i32 u64 i64 u128 i128);
|
||||
// * `ExactSizeIterator::len` is required to always return an exact `usize`,
|
||||
// so no range can be longer than `usize::MAX`.
|
||||
// * For integer types in `Range<_>` this is the case for types narrower than or as wide as `usize`.
|
||||
// For integer types in `RangeInclusive<_>`
|
||||
// this is the case for types *strictly narrower* than `usize`
|
||||
// since e.g. `(0..=u64::MAX).len()` would be `u64::MAX + 1`.
|
||||
range_exact_iter_impl! {
|
||||
usize u8 u16
|
||||
isize i8 i16
|
||||
|
||||
// These are incorect per the reasoning above,
|
||||
// but removing them would be a breaking change as they were stabilized in Rust 1.0.0.
|
||||
// So e.g. `(0..66_000_u32).len()` for example will compile without error or warnings
|
||||
// on 16-bit platforms, but continue to give a wrong result.
|
||||
u32
|
||||
i32
|
||||
}
|
||||
range_incl_exact_iter_impl! {
|
||||
u8
|
||||
i8
|
||||
|
||||
// These are incorect per the reasoning above,
|
||||
// but removing them would be a breaking change as they were stabilized in Rust 1.26.0.
|
||||
// So e.g. `(0..=u16::MAX).len()` for example will compile without error or warnings
|
||||
// on 16-bit platforms, but continue to give a wrong result.
|
||||
u16
|
||||
i16
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl<A: Step> DoubleEndedIterator for ops::Range<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A> {
|
||||
if self.start < self.end {
|
||||
self.end = self.end.sub_one();
|
||||
self.end = Step::backward(self.end.clone(), 1);
|
||||
Some(self.end.clone())
|
||||
} else {
|
||||
None
|
||||
@ -289,9 +516,9 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
|
||||
|
||||
#[inline]
|
||||
fn nth_back(&mut self, n: usize) -> Option<A> {
|
||||
if let Some(minus_n) = self.end.sub_usize(n) {
|
||||
if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
|
||||
if minus_n > self.start {
|
||||
self.end = minus_n.sub_one();
|
||||
self.end = Step::backward(minus_n, 1);
|
||||
return Some(self.end.clone());
|
||||
}
|
||||
}
|
||||
@ -301,6 +528,9 @@ impl<A: Step> DoubleEndedIterator for ops::Range<A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: Step> TrustedLen for ops::Range<A> {}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl<A: Step> FusedIterator for ops::Range<A> {}
|
||||
|
||||
@ -310,9 +540,8 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A> {
|
||||
let mut n = self.start.add_one();
|
||||
mem::swap(&mut n, &mut self.start);
|
||||
Some(n)
|
||||
let n = Step::forward(self.start.clone(), 1);
|
||||
Some(mem::replace(&mut self.start, n))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -322,8 +551,16 @@ impl<A: Step> Iterator for ops::RangeFrom<A> {
|
||||
|
||||
#[inline]
|
||||
fn nth(&mut self, n: usize) -> Option<A> {
|
||||
let plus_n = self.start.add_usize(n).expect("overflow in RangeFrom::nth");
|
||||
self.start = plus_n.add_one();
|
||||
// If we would jump over the maximum value, panic immediately.
|
||||
// This is consistent with behavior before the Step redesign,
|
||||
// even though it's inconsistent with n `next` calls.
|
||||
// To get consistent behavior, change it to use `forward` instead.
|
||||
// This change should go through FCP separately to the redesign, so is for now left as a
|
||||
// FIXME: make this consistent
|
||||
let plus_n =
|
||||
Step::forward_checked(self.start.clone(), n).expect("overflow in RangeFrom::nth");
|
||||
// The final step should always be debug-checked.
|
||||
self.start = Step::forward(plus_n.clone(), 1);
|
||||
Some(plus_n)
|
||||
}
|
||||
}
|
||||
@ -345,7 +582,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
||||
}
|
||||
let is_iterating = self.start < self.end;
|
||||
Some(if is_iterating {
|
||||
let n = self.start.add_one();
|
||||
let n = Step::forward(self.start.clone(), 1);
|
||||
mem::replace(&mut self.start, n)
|
||||
} else {
|
||||
self.exhausted = true;
|
||||
@ -371,12 +608,12 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(plus_n) = self.start.add_usize(n) {
|
||||
if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) {
|
||||
use crate::cmp::Ordering::*;
|
||||
|
||||
match plus_n.partial_cmp(&self.end) {
|
||||
Some(Less) => {
|
||||
self.start = plus_n.add_one();
|
||||
self.start = Step::forward(plus_n.clone(), 1);
|
||||
return Some(plus_n);
|
||||
}
|
||||
Some(Equal) => {
|
||||
@ -407,7 +644,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> {
|
||||
let mut accum = init;
|
||||
|
||||
while self.start < self.end {
|
||||
let n = self.start.add_one();
|
||||
let n = Step::forward(self.start.clone(), 1);
|
||||
let n = mem::replace(&mut self.start, n);
|
||||
accum = f(accum, n)?;
|
||||
}
|
||||
@ -446,7 +683,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
||||
}
|
||||
let is_iterating = self.start < self.end;
|
||||
Some(if is_iterating {
|
||||
let n = self.end.sub_one();
|
||||
let n = Step::backward(self.end.clone(), 1);
|
||||
mem::replace(&mut self.end, n)
|
||||
} else {
|
||||
self.exhausted = true;
|
||||
@ -460,12 +697,12 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
||||
return None;
|
||||
}
|
||||
|
||||
if let Some(minus_n) = self.end.sub_usize(n) {
|
||||
if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) {
|
||||
use crate::cmp::Ordering::*;
|
||||
|
||||
match minus_n.partial_cmp(&self.start) {
|
||||
Some(Greater) => {
|
||||
self.end = minus_n.sub_one();
|
||||
self.end = Step::backward(minus_n.clone(), 1);
|
||||
return Some(minus_n);
|
||||
}
|
||||
Some(Equal) => {
|
||||
@ -496,7 +733,7 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
||||
let mut accum = init;
|
||||
|
||||
while self.start < self.end {
|
||||
let n = self.end.sub_one();
|
||||
let n = Step::backward(self.end.clone(), 1);
|
||||
let n = mem::replace(&mut self.end, n);
|
||||
accum = f(accum, n)?;
|
||||
}
|
||||
@ -511,5 +748,8 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> {
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
unsafe impl<A: Step> TrustedLen for ops::RangeInclusive<A> {}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
impl<A: Step> FusedIterator for ops::RangeInclusive<A> {}
|
||||
|
@ -333,7 +333,7 @@ pub trait Iterator {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
|
||||
for x in self {
|
||||
while let Some(x) = self.next() {
|
||||
if n == 0 {
|
||||
return Some(x);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@
|
||||
/// [`Iterator::fuse`]: ../../std/iter/trait.Iterator.html#method.fuse
|
||||
/// [`Fuse`]: ../../std/iter/struct.Fuse.html
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
pub trait FusedIterator: Iterator {}
|
||||
|
||||
#[stable(feature = "fused", since = "1.26.0")]
|
||||
@ -38,6 +39,7 @@ impl<I: FusedIterator + ?Sized> FusedIterator for &mut I {}
|
||||
/// [`usize::MAX`]: ../../std/usize/constant.MAX.html
|
||||
/// [`.size_hint`]: ../../std/iter/trait.Iterator.html#method.size_hint
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
pub unsafe trait TrustedLen: Iterator {}
|
||||
|
||||
#[unstable(feature = "trusted_len", issue = "37572")]
|
||||
|
@ -363,6 +363,13 @@ pub trait StructuralEq {
|
||||
/// [impls]: #implementors
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[lang = "copy"]
|
||||
// FIXME(matthewjasper) This allows copying a type that doesn't implement
|
||||
// `Copy` because of unsatisfied lifetime bounds (copying `A<'_>` when only
|
||||
// `A<'static>: Copy` and `A<'_>: Clone`).
|
||||
// We have this attribute here for now only because there are quite a few
|
||||
// existing specializations on `Copy` that already exist in the standard
|
||||
// library, and there's no way to safely have this behavior right now.
|
||||
#[rustc_unsafe_specialization_marker]
|
||||
pub trait Copy: Clone {
|
||||
// Empty.
|
||||
}
|
||||
|
@ -2,19 +2,23 @@ use crate::ops::{Deref, DerefMut};
|
||||
use crate::ptr;
|
||||
|
||||
/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
|
||||
///
|
||||
/// This wrapper is 0-cost.
|
||||
///
|
||||
/// `ManuallyDrop<T>` is subject to the same layout optimizations as `T`.
|
||||
/// As a consequence, it has *no effect* on the assumptions that the compiler makes
|
||||
/// about all values being initialized at their type. In particular, initializing
|
||||
/// a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined behavior.
|
||||
/// about its contents. For example, initializing a `ManuallyDrop<&mut T>`
|
||||
/// with [`mem::zeroed`] is undefined behavior.
|
||||
/// If you need to handle uninitialized data, use [`MaybeUninit<T>`] instead.
|
||||
///
|
||||
/// Note that accessing the value inside a `ManuallyDrop<T>` is safe.
|
||||
/// This means that a `ManuallyDrop<T>` whose content has been dropped must not
|
||||
/// be exposed through a public safe API.
|
||||
/// Correspondingly, `ManuallyDrop::drop` is unsafe.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// This wrapper helps with explicitly documenting the drop order dependencies between fields of
|
||||
/// the type:
|
||||
/// This wrapper can be used to enforce a particular drop order on fields, regardless
|
||||
/// of how they are defined in the struct:
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::mem::ManuallyDrop;
|
||||
@ -43,8 +47,18 @@ use crate::ptr;
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// However, care should be taken when using this pattern as it can lead to *leak amplification*.
|
||||
/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field
|
||||
/// would also be leaked.
|
||||
///
|
||||
/// In contrast, the automatically-generated compiler drop implementation would have ensured
|
||||
/// that all fields are dropped even in the presence of panics. This is especially important when
|
||||
/// working with [pinned] data, where reusing the memory without calling the destructor could lead
|
||||
/// to Undefined Behaviour.
|
||||
///
|
||||
/// [`mem::zeroed`]: fn.zeroed.html
|
||||
/// [`MaybeUninit<T>`]: union.MaybeUninit.html
|
||||
/// [pinned]: ../pin/index.html
|
||||
#[stable(feature = "manually_drop", since = "1.20.0")]
|
||||
#[lang = "manually_drop"]
|
||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
@ -113,19 +127,28 @@ impl<T> ManuallyDrop<T> {
|
||||
}
|
||||
|
||||
impl<T: ?Sized> ManuallyDrop<T> {
|
||||
/// Manually drops the contained value.
|
||||
/// Manually drops the contained value. This is exactly equivalent to calling
|
||||
/// [`ptr::drop_in_place`] with a pointer to the contained value. As such, unless
|
||||
/// the contained value is a packed struct, the destructor will be called in-place
|
||||
/// without moving the value, and thus can be used to safely drop [pinned] data.
|
||||
///
|
||||
/// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function runs the destructor of the contained value and thus the wrapped value
|
||||
/// now represents uninitialized data. It is up to the user of this method to ensure the
|
||||
/// uninitialized data is not actually used.
|
||||
/// In particular, this function can only be called at most once
|
||||
/// for a given instance of `ManuallyDrop<T>`.
|
||||
/// This function runs the destructor of the contained value. Other than changes made by
|
||||
/// the destructor itself, the memory is left unchanged, and so as far as the compiler is
|
||||
/// concerned still holds a bit-pattern which is valid for the type `T`.
|
||||
///
|
||||
/// However, this "zombie" value should not be exposed to safe code, and this function
|
||||
/// should not be called more than once. To use a value after it's been dropped, or drop
|
||||
/// a value multiple times, can cause Undefined Behavior (depending on what `drop` does).
|
||||
/// This is normally prevented by the type system, but users of `ManuallyDrop` must
|
||||
/// uphold those guarantees without assistance from the compiler.
|
||||
///
|
||||
/// [`ManuallyDrop::into_inner`]: #method.into_inner
|
||||
/// [`ptr::drop_in_place`]: ../ptr/fn.drop_in_place.html
|
||||
/// [pinned]: ../pin/index.html
|
||||
#[stable(feature = "manually_drop", since = "1.20.0")]
|
||||
#[inline]
|
||||
pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
|
||||
|
@ -367,7 +367,7 @@ impl f32 {
|
||||
/// Infinity (∞).
|
||||
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
|
||||
pub const INFINITY: f32 = 1.0_f32 / 0.0_f32;
|
||||
/// Negative infinity (-∞).
|
||||
/// Negative infinity (−∞).
|
||||
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
|
||||
pub const NEG_INFINITY: f32 = -1.0_f32 / 0.0_f32;
|
||||
|
||||
|
@ -366,7 +366,7 @@ impl f64 {
|
||||
/// Infinity (∞).
|
||||
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
|
||||
pub const INFINITY: f64 = 1.0_f64 / 0.0_f64;
|
||||
/// Negative infinity (-∞).
|
||||
/// Negative infinity (−∞).
|
||||
#[stable(feature = "assoc_int_consts", since = "1.43.0")]
|
||||
pub const NEG_INFINITY: f64 = -1.0_f64 / 0.0_f64;
|
||||
|
||||
|
@ -749,6 +749,23 @@ $EndFeature, "
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Unchecked integer addition. Computes `self + rhs, assuming overflow
|
||||
cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
|
||||
"::max_value()` or `self + rhs < ", stringify!($SelfT), "::min_value()`."),
|
||||
#[unstable(
|
||||
feature = "unchecked_math",
|
||||
reason = "niche optimization path",
|
||||
issue = "none",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
|
||||
intrinsics::unchecked_add(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if
|
||||
overflow occurred.
|
||||
@ -774,6 +791,23 @@ $EndFeature, "
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Unchecked integer subtraction. Computes `self - rhs, assuming overflow
|
||||
cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
|
||||
"::max_value()` or `self - rhs < ", stringify!($SelfT), "::min_value()`."),
|
||||
#[unstable(
|
||||
feature = "unchecked_math",
|
||||
reason = "niche optimization path",
|
||||
issue = "none",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
|
||||
intrinsics::unchecked_sub(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if
|
||||
overflow occurred.
|
||||
@ -799,6 +833,23 @@ $EndFeature, "
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Unchecked integer multiplication. Computes `self * rhs, assuming overflow
|
||||
cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
|
||||
"::max_value()` or `self * rhs < ", stringify!($SelfT), "::min_value()`."),
|
||||
#[unstable(
|
||||
feature = "unchecked_math",
|
||||
reason = "niche optimization path",
|
||||
issue = "none",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
|
||||
intrinsics::unchecked_mul(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0`
|
||||
or the division results in overflow.
|
||||
@ -1448,8 +1499,8 @@ any high-order bits of `rhs` that would cause the shift to exceed the bitwidth o
|
||||
|
||||
Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to
|
||||
the range of the type, rather than the bits shifted out of the LHS being returned to the other end.
|
||||
The primitive integer types all implement a `rotate_left` function, which may be what you want
|
||||
instead.
|
||||
The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function,
|
||||
which may be what you want instead.
|
||||
|
||||
# Examples
|
||||
|
||||
@ -1480,8 +1531,8 @@ removes any high-order bits of `rhs` that would cause the shift to exceed the bi
|
||||
|
||||
Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted
|
||||
to the range of the type, rather than the bits shifted out of the LHS being returned to the other
|
||||
end. The primitive integer types all implement a `rotate_right` function, which may be what you want
|
||||
instead.
|
||||
end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function,
|
||||
which may be what you want instead.
|
||||
|
||||
# Examples
|
||||
|
||||
@ -2936,6 +2987,23 @@ assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeat
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Unchecked integer addition. Computes `self + rhs, assuming overflow
|
||||
cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT),
|
||||
"::max_value()` or `self + rhs < ", stringify!($SelfT), "::min_value()`."),
|
||||
#[unstable(
|
||||
feature = "unchecked_math",
|
||||
reason = "niche optimization path",
|
||||
issue = "none",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_add(self, rhs: Self) -> Self {
|
||||
intrinsics::unchecked_add(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Checked integer subtraction. Computes `self - rhs`, returning
|
||||
`None` if overflow occurred.
|
||||
@ -2959,6 +3027,23 @@ assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, "
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Unchecked integer subtraction. Computes `self - rhs, assuming overflow
|
||||
cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT),
|
||||
"::max_value()` or `self - rhs < ", stringify!($SelfT), "::min_value()`."),
|
||||
#[unstable(
|
||||
feature = "unchecked_math",
|
||||
reason = "niche optimization path",
|
||||
issue = "none",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_sub(self, rhs: Self) -> Self {
|
||||
intrinsics::unchecked_sub(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Checked integer multiplication. Computes `self * rhs`, returning
|
||||
`None` if overflow occurred.
|
||||
@ -2982,6 +3067,23 @@ assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, "
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Unchecked integer multiplication. Computes `self * rhs, assuming overflow
|
||||
cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT),
|
||||
"::max_value()` or `self * rhs < ", stringify!($SelfT), "::min_value()`."),
|
||||
#[unstable(
|
||||
feature = "unchecked_math",
|
||||
reason = "niche optimization path",
|
||||
issue = "none",
|
||||
)]
|
||||
#[must_use = "this returns the result of the operation, \
|
||||
without modifying the original"]
|
||||
#[inline]
|
||||
pub unsafe fn unchecked_mul(self, rhs: Self) -> Self {
|
||||
intrinsics::unchecked_mul(self, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
doc_comment! {
|
||||
concat!("Checked integer division. Computes `self / rhs`, returning `None`
|
||||
if `rhs == 0`.
|
||||
@ -3508,8 +3610,8 @@ Note that this is *not* the same as a rotate-left; the
|
||||
RHS of a wrapping shift-left is restricted to the range
|
||||
of the type, rather than the bits shifted out of the LHS
|
||||
being returned to the other end. The primitive integer
|
||||
types all implement a `rotate_left` function, which may
|
||||
be what you want instead.
|
||||
types all implement a [`rotate_left`](#method.rotate_left) function,
|
||||
which may be what you want instead.
|
||||
|
||||
# Examples
|
||||
|
||||
@ -3542,8 +3644,8 @@ Note that this is *not* the same as a rotate-right; the
|
||||
RHS of a wrapping shift-right is restricted to the range
|
||||
of the type, rather than the bits shifted out of the LHS
|
||||
being returned to the other end. The primitive integer
|
||||
types all implement a `rotate_right` function, which may
|
||||
be what you want instead.
|
||||
types all implement a [`rotate_right`](#method.rotate_right) function,
|
||||
which may be what you want instead.
|
||||
|
||||
# Examples
|
||||
|
||||
|
@ -1357,6 +1357,15 @@ impl<'a, T> IntoIterator for &'a mut Option<T> {
|
||||
|
||||
#[stable(since = "1.12.0", feature = "option_from")]
|
||||
impl<T> From<T> for Option<T> {
|
||||
/// Copies `val` into a new `Some`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let o: Option<u8> = Option::from(67);
|
||||
///
|
||||
/// assert_eq!(Some(67), o);
|
||||
/// ```
|
||||
fn from(val: T) -> Option<T> {
|
||||
Some(val)
|
||||
}
|
||||
@ -1364,6 +1373,27 @@ impl<T> From<T> for Option<T> {
|
||||
|
||||
#[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
|
||||
impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
|
||||
/// Converts from `&Option<T>` to `Option<&T>`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Converts an `Option<`[`String`]`>` into an `Option<`[`usize`]`>`, preserving the original.
|
||||
/// The [`map`] method takes the `self` argument by value, consuming the original,
|
||||
/// so this technique uses `as_ref` to first take an `Option` to a reference
|
||||
/// to the value inside the original.
|
||||
///
|
||||
/// [`map`]: ../../std/option/enum.Option.html#method.map
|
||||
/// [`String`]: ../../std/string/struct.String.html
|
||||
/// [`usize`]: ../../std/primitive.usize.html
|
||||
///
|
||||
/// ```
|
||||
/// let s: Option<String> = Some(String::from("Hello, Rustaceans!"));
|
||||
/// let o: Option<usize> = Option::from(&s).map(|ss: &String| ss.len());
|
||||
///
|
||||
/// println!("Can still print s: {:?}", s);
|
||||
///
|
||||
/// assert_eq!(o, Some(18));
|
||||
/// ```
|
||||
fn from(o: &'a Option<T>) -> Option<&'a T> {
|
||||
o.as_ref()
|
||||
}
|
||||
@ -1371,6 +1401,21 @@ impl<'a, T> From<&'a Option<T>> for Option<&'a T> {
|
||||
|
||||
#[stable(feature = "option_ref_from_ref_option", since = "1.30.0")]
|
||||
impl<'a, T> From<&'a mut Option<T>> for Option<&'a mut T> {
|
||||
/// Converts from `&mut Option<T>` to `Option<&mut T>`
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// let mut s = Some(String::from("Hello"));
|
||||
/// let o: Option<&mut String> = Option::from(&mut s);
|
||||
///
|
||||
/// match o {
|
||||
/// Some(t) => *t = String::from("Hello, Rustaceans!"),
|
||||
/// None => (),
|
||||
/// }
|
||||
///
|
||||
/// assert_eq!(s, Some(String::from("Hello, Rustaceans!")));
|
||||
/// ```
|
||||
fn from(o: &'a mut Option<T>) -> Option<&'a mut T> {
|
||||
o.as_mut()
|
||||
}
|
||||
|
@ -39,8 +39,12 @@ use crate::panic::{Location, PanicInfo};
|
||||
#[lang = "panic"] // needed by codegen for panic on overflow and other `Assert` MIR terminators
|
||||
pub fn panic(expr: &str) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
// remove `unsafe` (and safety comment) on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
// SAFETY: the `abort` intrinsic has no requirements to be called.
|
||||
unsafe { super::intrinsics::abort() }
|
||||
unsafe {
|
||||
super::intrinsics::abort()
|
||||
}
|
||||
}
|
||||
|
||||
// Use Arguments::new_v1 instead of format_args!("{}", expr) to potentially
|
||||
@ -58,8 +62,12 @@ pub fn panic(expr: &str) -> ! {
|
||||
#[lang = "panic_bounds_check"] // needed by codegen for panic on OOB array/slice access
|
||||
fn panic_bounds_check(index: usize, len: usize) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
// remove `unsafe` (and safety comment) on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
// SAFETY: the `abort` intrinsic has no requirements to be called.
|
||||
unsafe { super::intrinsics::abort() }
|
||||
unsafe {
|
||||
super::intrinsics::abort()
|
||||
}
|
||||
}
|
||||
|
||||
panic!("index out of bounds: the len is {} but the index is {}", len, index)
|
||||
@ -72,8 +80,12 @@ fn panic_bounds_check(index: usize, len: usize) -> ! {
|
||||
#[track_caller]
|
||||
pub fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
|
||||
if cfg!(feature = "panic_immediate_abort") {
|
||||
// remove `unsafe` (and safety comment) on bootstrap bump
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))]
|
||||
// SAFETY: the `abort` intrinsic has no requirements to be called.
|
||||
unsafe { super::intrinsics::abort() }
|
||||
unsafe {
|
||||
super::intrinsics::abort()
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call
|
||||
|
@ -110,11 +110,17 @@ mod mut_ptr;
|
||||
/// as the compiler doesn't need to prove that it's sound to elide the
|
||||
/// copy.
|
||||
///
|
||||
/// * It can be used to drop [pinned] data when `T` is not `repr(packed)`
|
||||
/// (pinned data must not be moved before it is dropped).
|
||||
///
|
||||
/// Unaligned values cannot be dropped in place, they must be copied to an aligned
|
||||
/// location first using [`ptr::read_unaligned`].
|
||||
/// location first using [`ptr::read_unaligned`]. For packed structs, this move is
|
||||
/// done automatically by the compiler. This means the fields of packed structs
|
||||
/// are not dropped in-place.
|
||||
///
|
||||
/// [`ptr::read`]: ../ptr/fn.read.html
|
||||
/// [`ptr::read_unaligned`]: ../ptr/fn.read_unaligned.html
|
||||
/// [pinned]: ../pin/index.html
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
|
@ -3179,6 +3179,7 @@ macro_rules! is_empty {
|
||||
$self.ptr.as_ptr() as *const T == $self.end
|
||||
};
|
||||
}
|
||||
|
||||
// To get rid of some bounds checks (see `position`), we compute the length in a somewhat
|
||||
// unexpected way. (Tested by `codegen/slice-position-bounds-check`.)
|
||||
macro_rules! len {
|
||||
@ -3347,40 +3348,127 @@ macro_rules! iterator {
|
||||
self.next_back()
|
||||
}
|
||||
|
||||
// We override the default implementation, which uses `try_fold`,
|
||||
// because this simple implementation generates less LLVM IR and is
|
||||
// faster to compile.
|
||||
#[inline]
|
||||
fn for_each<F>(mut self, mut f: F)
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Item),
|
||||
{
|
||||
while let Some(x) = self.next() {
|
||||
f(x);
|
||||
}
|
||||
}
|
||||
|
||||
// We override the default implementation, which uses `try_fold`,
|
||||
// because this simple implementation generates less LLVM IR and is
|
||||
// faster to compile.
|
||||
#[inline]
|
||||
fn all<F>(&mut self, mut f: F) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
while let Some(x) = self.next() {
|
||||
if !f(x) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
// We override the default implementation, which uses `try_fold`,
|
||||
// because this simple implementation generates less LLVM IR and is
|
||||
// faster to compile.
|
||||
#[inline]
|
||||
fn any<F>(&mut self, mut f: F) -> bool
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
while let Some(x) = self.next() {
|
||||
if f(x) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
// We override the default implementation, which uses `try_fold`,
|
||||
// because this simple implementation generates less LLVM IR and is
|
||||
// faster to compile.
|
||||
#[inline]
|
||||
fn find<P>(&mut self, mut predicate: P) -> Option<Self::Item>
|
||||
where
|
||||
Self: Sized,
|
||||
P: FnMut(&Self::Item) -> bool,
|
||||
{
|
||||
while let Some(x) = self.next() {
|
||||
if predicate(&x) {
|
||||
return Some(x);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// We override the default implementation, which uses `try_fold`,
|
||||
// because this simple implementation generates less LLVM IR and is
|
||||
// faster to compile.
|
||||
#[inline]
|
||||
fn find_map<B, F>(&mut self, mut f: F) -> Option<B>
|
||||
where
|
||||
Self: Sized,
|
||||
F: FnMut(Self::Item) -> Option<B>,
|
||||
{
|
||||
while let Some(x) = self.next() {
|
||||
if let Some(y) = f(x) {
|
||||
return Some(y);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// We override the default implementation, which uses `try_fold`,
|
||||
// because this simple implementation generates less LLVM IR and is
|
||||
// faster to compile. Also, the `assume` avoids a bounds check.
|
||||
#[inline]
|
||||
#[rustc_inherit_overflow_checks]
|
||||
fn position<P>(&mut self, mut predicate: P) -> Option<usize> where
|
||||
Self: Sized,
|
||||
P: FnMut(Self::Item) -> bool,
|
||||
{
|
||||
// The addition might panic on overflow.
|
||||
let n = len!(self);
|
||||
self.try_fold(0, move |i, x| {
|
||||
if predicate(x) { Err(i) }
|
||||
else { Ok(i + 1) }
|
||||
}).err()
|
||||
.map(|i| {
|
||||
let mut i = 0;
|
||||
while let Some(x) = self.next() {
|
||||
if predicate(x) {
|
||||
unsafe { assume(i < n) };
|
||||
i
|
||||
})
|
||||
return Some(i);
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
// We override the default implementation, which uses `try_fold`,
|
||||
// because this simple implementation generates less LLVM IR and is
|
||||
// faster to compile. Also, the `assume` avoids a bounds check.
|
||||
#[inline]
|
||||
fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
|
||||
P: FnMut(Self::Item) -> bool,
|
||||
Self: Sized + ExactSizeIterator + DoubleEndedIterator
|
||||
{
|
||||
// No need for an overflow check here, because `ExactSizeIterator`
|
||||
let n = len!(self);
|
||||
self.try_rfold(n, move |i, x| {
|
||||
let i = i - 1;
|
||||
if predicate(x) { Err(i) }
|
||||
else { Ok(i) }
|
||||
}).err()
|
||||
.map(|i| {
|
||||
let mut i = n;
|
||||
while let Some(x) = self.next_back() {
|
||||
i -= 1;
|
||||
if predicate(x) {
|
||||
unsafe { assume(i < n) };
|
||||
i
|
||||
})
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
$($extra)*
|
||||
|
@ -2139,6 +2139,24 @@ fn test_range_inclusive_nth_back() {
|
||||
assert_eq!(ExactSizeIterator::is_empty(&r), true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_len() {
|
||||
assert_eq!((0..10_u8).len(), 10);
|
||||
assert_eq!((9..10_u8).len(), 1);
|
||||
assert_eq!((10..10_u8).len(), 0);
|
||||
assert_eq!((11..10_u8).len(), 0);
|
||||
assert_eq!((100..10_u8).len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_inclusive_len() {
|
||||
assert_eq!((0..=10_u8).len(), 11);
|
||||
assert_eq!((9..=10_u8).len(), 2);
|
||||
assert_eq!((10..=10_u8).len(), 1);
|
||||
assert_eq!((11..=10_u8).len(), 0);
|
||||
assert_eq!((100..=10_u8).len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_range_step() {
|
||||
#![allow(deprecated)]
|
||||
@ -2509,42 +2527,91 @@ fn test_chain_fold() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_step_replace_unsigned() {
|
||||
let mut x = 4u32;
|
||||
let y = x.replace_zero();
|
||||
assert_eq!(x, 0);
|
||||
assert_eq!(y, 4);
|
||||
fn test_steps_between() {
|
||||
assert_eq!(Step::steps_between(&20_u8, &200_u8), Some(180_usize));
|
||||
assert_eq!(Step::steps_between(&-20_i8, &80_i8), Some(100_usize));
|
||||
assert_eq!(Step::steps_between(&-120_i8, &80_i8), Some(200_usize));
|
||||
assert_eq!(Step::steps_between(&20_u32, &4_000_100_u32), Some(4_000_080_usize));
|
||||
assert_eq!(Step::steps_between(&-20_i32, &80_i32), Some(100_usize));
|
||||
assert_eq!(Step::steps_between(&-2_000_030_i32, &2_000_050_i32), Some(4_000_080_usize));
|
||||
|
||||
x = 5;
|
||||
let y = x.replace_one();
|
||||
assert_eq!(x, 1);
|
||||
assert_eq!(y, 5);
|
||||
// Skip u64/i64 to avoid differences with 32-bit vs 64-bit platforms
|
||||
|
||||
assert_eq!(Step::steps_between(&20_u128, &200_u128), Some(180_usize));
|
||||
assert_eq!(Step::steps_between(&-20_i128, &80_i128), Some(100_usize));
|
||||
if cfg!(target_pointer_width = "64") {
|
||||
assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_0009_u128), Some(usize::MAX));
|
||||
}
|
||||
assert_eq!(Step::steps_between(&10_u128, &0x1_0000_0000_0000_000a_u128), None);
|
||||
assert_eq!(Step::steps_between(&10_i128, &0x1_0000_0000_0000_000a_i128), None);
|
||||
assert_eq!(
|
||||
Step::steps_between(&-0x1_0000_0000_0000_0000_i128, &0x1_0000_0000_0000_0000_i128,),
|
||||
None,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_step_replace_signed() {
|
||||
let mut x = 4i32;
|
||||
let y = x.replace_zero();
|
||||
assert_eq!(x, 0);
|
||||
assert_eq!(y, 4);
|
||||
fn test_step_forward() {
|
||||
assert_eq!(Step::forward_checked(55_u8, 200_usize), Some(255_u8));
|
||||
assert_eq!(Step::forward_checked(252_u8, 200_usize), None);
|
||||
assert_eq!(Step::forward_checked(0_u8, 256_usize), None);
|
||||
assert_eq!(Step::forward_checked(-110_i8, 200_usize), Some(90_i8));
|
||||
assert_eq!(Step::forward_checked(-110_i8, 248_usize), None);
|
||||
assert_eq!(Step::forward_checked(-126_i8, 256_usize), None);
|
||||
|
||||
x = 5;
|
||||
let y = x.replace_one();
|
||||
assert_eq!(x, 1);
|
||||
assert_eq!(y, 5);
|
||||
assert_eq!(Step::forward_checked(35_u16, 100_usize), Some(135_u16));
|
||||
assert_eq!(Step::forward_checked(35_u16, 65500_usize), Some(u16::MAX));
|
||||
assert_eq!(Step::forward_checked(36_u16, 65500_usize), None);
|
||||
assert_eq!(Step::forward_checked(-110_i16, 200_usize), Some(90_i16));
|
||||
assert_eq!(Step::forward_checked(-20_030_i16, 50_050_usize), Some(30_020_i16));
|
||||
assert_eq!(Step::forward_checked(-10_i16, 40_000_usize), None);
|
||||
assert_eq!(Step::forward_checked(-10_i16, 70_000_usize), None);
|
||||
|
||||
assert_eq!(Step::forward_checked(10_u128, 70_000_usize), Some(70_010_u128));
|
||||
assert_eq!(Step::forward_checked(10_i128, 70_030_usize), Some(70_040_i128));
|
||||
assert_eq!(
|
||||
Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0xff_usize),
|
||||
Some(u128::MAX),
|
||||
);
|
||||
assert_eq!(
|
||||
Step::forward_checked(0xffff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_u128, 0x100_usize),
|
||||
None
|
||||
);
|
||||
assert_eq!(
|
||||
Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0xff_usize),
|
||||
Some(i128::MAX),
|
||||
);
|
||||
assert_eq!(
|
||||
Step::forward_checked(0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
|
||||
None
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_step_replace_no_between() {
|
||||
let mut x = 4u128;
|
||||
let y = x.replace_zero();
|
||||
assert_eq!(x, 0);
|
||||
assert_eq!(y, 4);
|
||||
fn test_step_backward() {
|
||||
assert_eq!(Step::backward_checked(255_u8, 200_usize), Some(55_u8));
|
||||
assert_eq!(Step::backward_checked(100_u8, 200_usize), None);
|
||||
assert_eq!(Step::backward_checked(255_u8, 256_usize), None);
|
||||
assert_eq!(Step::backward_checked(90_i8, 200_usize), Some(-110_i8));
|
||||
assert_eq!(Step::backward_checked(110_i8, 248_usize), None);
|
||||
assert_eq!(Step::backward_checked(127_i8, 256_usize), None);
|
||||
|
||||
x = 5;
|
||||
let y = x.replace_one();
|
||||
assert_eq!(x, 1);
|
||||
assert_eq!(y, 5);
|
||||
assert_eq!(Step::backward_checked(135_u16, 100_usize), Some(35_u16));
|
||||
assert_eq!(Step::backward_checked(u16::MAX, 65500_usize), Some(35_u16));
|
||||
assert_eq!(Step::backward_checked(10_u16, 11_usize), None);
|
||||
assert_eq!(Step::backward_checked(90_i16, 200_usize), Some(-110_i16));
|
||||
assert_eq!(Step::backward_checked(30_020_i16, 50_050_usize), Some(-20_030_i16));
|
||||
assert_eq!(Step::backward_checked(-10_i16, 40_000_usize), None);
|
||||
assert_eq!(Step::backward_checked(-10_i16, 70_000_usize), None);
|
||||
|
||||
assert_eq!(Step::backward_checked(70_010_u128, 70_000_usize), Some(10_u128));
|
||||
assert_eq!(Step::backward_checked(70_020_i128, 70_030_usize), Some(-10_i128));
|
||||
assert_eq!(Step::backward_checked(10_u128, 7_usize), Some(3_u128));
|
||||
assert_eq!(Step::backward_checked(10_u128, 11_usize), None);
|
||||
assert_eq!(
|
||||
Step::backward_checked(-0x7fff_ffff_ffff_ffff__ffff_ffff_ffff_ff00_i128, 0x100_usize),
|
||||
Some(i128::MIN)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -22,6 +22,7 @@
|
||||
#![feature(slice_partition_at_index)]
|
||||
#![feature(specialization)]
|
||||
#![feature(step_trait)]
|
||||
#![feature(step_trait_ext)]
|
||||
#![feature(str_internals)]
|
||||
#![feature(test)]
|
||||
#![feature(trusted_len)]
|
||||
|
@ -327,5 +327,8 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
|
||||
#[lang = "eh_personality"]
|
||||
#[cfg(not(test))]
|
||||
fn rust_eh_personality() {
|
||||
unsafe { core::intrinsics::abort() }
|
||||
#[cfg_attr(not(bootstrap), allow(unused_unsafe))] // remove `unsafe` on bootstrap bump
|
||||
unsafe {
|
||||
core::intrinsics::abort()
|
||||
}
|
||||
}
|
||||
|
@ -202,10 +202,16 @@ impl Clone for Literal {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
|
||||
impl fmt::Debug for Literal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(&self.debug())
|
||||
f.debug_struct("Literal")
|
||||
// format the kind without quotes, as in `kind: Float`
|
||||
.field("kind", &format_args!("{}", &self.debug_kind()))
|
||||
.field("symbol", &self.symbol())
|
||||
// format `Some("...")` on one line even in {:#?} mode
|
||||
.field("suffix", &format_args!("{:?}", &self.suffix()))
|
||||
.field("span", &self.span())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,8 +103,9 @@ macro_rules! with_api {
|
||||
Literal {
|
||||
fn drop($self: $S::Literal);
|
||||
fn clone($self: &$S::Literal) -> $S::Literal;
|
||||
// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
|
||||
fn debug($self: &$S::Literal) -> String;
|
||||
fn debug_kind($self: &$S::Literal) -> String;
|
||||
fn symbol($self: &$S::Literal) -> String;
|
||||
fn suffix($self: &$S::Literal) -> Option<String>;
|
||||
fn integer(n: &str) -> $S::Literal;
|
||||
fn typed_integer(n: &str, kind: &str) -> $S::Literal;
|
||||
fn float(n: &str) -> $S::Literal;
|
||||
|
@ -158,6 +158,13 @@ impl fmt::Debug for TokenStream {
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "proc_macro_token_stream_default", since = "1.45.0")]
|
||||
impl Default for TokenStream {
|
||||
fn default() -> Self {
|
||||
TokenStream::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[unstable(feature = "proc_macro_quote", issue = "54722")]
|
||||
pub use quote::{quote, quote_span};
|
||||
|
||||
@ -1134,7 +1141,6 @@ impl fmt::Display for Literal {
|
||||
#[stable(feature = "proc_macro_lib2", since = "1.29.0")]
|
||||
impl fmt::Debug for Literal {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,7 @@ use crate::tokenstream::TokenTree;
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_lexer::unescape::{unescape_byte, unescape_char};
|
||||
use rustc_lexer::unescape::{unescape_byte_str, unescape_str};
|
||||
use rustc_lexer::unescape::{unescape_raw_byte_str, unescape_raw_str};
|
||||
use rustc_lexer::unescape::{unescape_byte_literal, unescape_literal, Mode};
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
@ -59,45 +58,53 @@ impl LitKind {
|
||||
// new symbol because the string in the LitKind is different to the
|
||||
// string in the token.
|
||||
let s = symbol.as_str();
|
||||
let symbol = if s.contains(&['\\', '\r'][..]) {
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_str(&s, &mut |_, unescaped_char| match unescaped_char {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(_) => error = Err(LitError::LexerError),
|
||||
});
|
||||
error?;
|
||||
Symbol::intern(&buf)
|
||||
} else {
|
||||
symbol
|
||||
};
|
||||
let symbol =
|
||||
if s.contains(&['\\', '\r'][..]) {
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| {
|
||||
match unescaped_char {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(_) => error = Err(LitError::LexerError),
|
||||
}
|
||||
});
|
||||
error?;
|
||||
Symbol::intern(&buf)
|
||||
} else {
|
||||
symbol
|
||||
};
|
||||
LitKind::Str(symbol, ast::StrStyle::Cooked)
|
||||
}
|
||||
token::StrRaw(n) => {
|
||||
// Ditto.
|
||||
let s = symbol.as_str();
|
||||
let symbol = if s.contains('\r') {
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_raw_str(&s, &mut |_, unescaped_char| match unescaped_char {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(_) => error = Err(LitError::LexerError),
|
||||
});
|
||||
error?;
|
||||
buf.shrink_to_fit();
|
||||
Symbol::intern(&buf)
|
||||
} else {
|
||||
symbol
|
||||
};
|
||||
let symbol =
|
||||
if s.contains('\r') {
|
||||
let mut buf = String::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| {
|
||||
match unescaped_char {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(_) => error = Err(LitError::LexerError),
|
||||
}
|
||||
});
|
||||
error?;
|
||||
buf.shrink_to_fit();
|
||||
Symbol::intern(&buf)
|
||||
} else {
|
||||
symbol
|
||||
};
|
||||
LitKind::Str(symbol, ast::StrStyle::Raw(n))
|
||||
}
|
||||
token::ByteStr => {
|
||||
let s = symbol.as_str();
|
||||
let mut buf = Vec::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_byte_str(&s, &mut |_, unescaped_byte| match unescaped_byte {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(_) => error = Err(LitError::LexerError),
|
||||
unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| {
|
||||
match unescaped_byte {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(_) => error = Err(LitError::LexerError),
|
||||
}
|
||||
});
|
||||
error?;
|
||||
buf.shrink_to_fit();
|
||||
@ -108,9 +115,11 @@ impl LitKind {
|
||||
let bytes = if s.contains('\r') {
|
||||
let mut buf = Vec::with_capacity(s.len());
|
||||
let mut error = Ok(());
|
||||
unescape_raw_byte_str(&s, &mut |_, unescaped_byte| match unescaped_byte {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(_) => error = Err(LitError::LexerError),
|
||||
unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| {
|
||||
match unescaped_byte {
|
||||
Ok(c) => buf.push(c),
|
||||
Err(_) => error = Err(LitError::LexerError),
|
||||
}
|
||||
});
|
||||
error?;
|
||||
buf.shrink_to_fit();
|
||||
|
@ -33,7 +33,7 @@
|
||||
#![feature(array_value_iter)]
|
||||
#![feature(crate_visibility_modifier)]
|
||||
#![feature(marker_trait_attr)]
|
||||
#![feature(specialization)]
|
||||
#![feature(specialization)] // FIXME: min_specialization does not work
|
||||
#![feature(or_patterns)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
|
@ -572,6 +572,35 @@ impl<'a> AstValidator<'a> {
|
||||
.emit();
|
||||
}
|
||||
|
||||
fn check_nomangle_item_asciionly(&self, ident: Ident, item_span: Span) {
|
||||
if ident.name.as_str().is_ascii() {
|
||||
return;
|
||||
}
|
||||
let head_span = self.session.source_map().guess_head_span(item_span);
|
||||
struct_span_err!(
|
||||
self.session,
|
||||
head_span,
|
||||
E0754,
|
||||
"`#[no_mangle]` requires ASCII identifier"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
fn check_mod_file_item_asciionly(&self, ident: Ident) {
|
||||
if ident.name.as_str().is_ascii() {
|
||||
return;
|
||||
}
|
||||
struct_span_err!(
|
||||
self.session,
|
||||
ident.span,
|
||||
E0754,
|
||||
"trying to load file for module `{}` with non ascii identifer name",
|
||||
ident.name
|
||||
)
|
||||
.help("consider using `#[path]` attribute to specify filesystem path")
|
||||
.emit();
|
||||
}
|
||||
|
||||
fn deny_generic_params(&self, generics: &Generics, ident_span: Span) {
|
||||
if !generics.params.is_empty() {
|
||||
struct_span_err!(
|
||||
@ -866,6 +895,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
self.has_proc_macro_decls = true;
|
||||
}
|
||||
|
||||
if attr::contains_name(&item.attrs, sym::no_mangle) {
|
||||
self.check_nomangle_item_asciionly(item.ident, item.span);
|
||||
}
|
||||
|
||||
match item.kind {
|
||||
ItemKind::Impl {
|
||||
unsafety,
|
||||
@ -992,9 +1025,11 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
walk_list!(self, visit_attribute, &item.attrs);
|
||||
return;
|
||||
}
|
||||
ItemKind::Mod(_) => {
|
||||
ItemKind::Mod(Mod { inline, .. }) => {
|
||||
// Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
|
||||
attr::first_attr_value_str_by_name(&item.attrs, sym::path);
|
||||
if !inline && !attr::contains_name(&item.attrs, sym::path) {
|
||||
self.check_mod_file_item_asciionly(item.ident);
|
||||
}
|
||||
}
|
||||
ItemKind::Union(ref vdata, _) => {
|
||||
if let VariantData::Tuple(..) | VariantData::Unit(..) = vdata {
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Simply gives a rought count of the number of nodes in an AST.
|
||||
// Simply gives a rough count of the number of nodes in an AST.
|
||||
|
||||
use rustc_ast::ast::*;
|
||||
use rustc_ast::visit::*;
|
||||
|
@ -634,7 +634,7 @@ pub fn eval_condition(
|
||||
[NestedMetaItem::Literal(Lit { span, .. })
|
||||
| NestedMetaItem::MetaItem(MetaItem { span, .. })] => {
|
||||
sess.span_diagnostic
|
||||
.struct_span_err(*span, &*format!("expected a version literal"))
|
||||
.struct_span_err(*span, "expected a version literal")
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
|
@ -394,6 +394,7 @@ pub(crate) unsafe fn optimize_with_new_llvm_pass_manager(
|
||||
config.vectorize_slp,
|
||||
config.vectorize_loop,
|
||||
config.no_builtins,
|
||||
config.emit_lifetime_markers,
|
||||
sanitizer_options.as_ref(),
|
||||
pgo_gen_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
pgo_use_path.as_ref().map_or(std::ptr::null(), |s| s.as_ptr()),
|
||||
@ -934,10 +935,10 @@ pub unsafe fn with_llvm_pmb(
|
||||
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
|
||||
}
|
||||
(llvm::CodeGenOptLevel::None, ..) => {
|
||||
llvm::LLVMRustAddAlwaysInlinePass(builder, false);
|
||||
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
|
||||
}
|
||||
(llvm::CodeGenOptLevel::Less, ..) => {
|
||||
llvm::LLVMRustAddAlwaysInlinePass(builder, true);
|
||||
llvm::LLVMRustAddAlwaysInlinePass(builder, config.emit_lifetime_markers);
|
||||
}
|
||||
(llvm::CodeGenOptLevel::Default, ..) => {
|
||||
llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
|
||||
|
@ -18,7 +18,6 @@ use rustc_data_structures::small_c_str::SmallCStr;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::config::{self, Sanitizer};
|
||||
use rustc_target::abi::{self, Align, Size};
|
||||
use rustc_target::spec::{HasTargetSpec, Target};
|
||||
use std::borrow::Cow;
|
||||
@ -1243,14 +1242,7 @@ impl Builder<'a, 'll, 'tcx> {
|
||||
return;
|
||||
}
|
||||
|
||||
let opts = &self.cx.sess().opts;
|
||||
let emit = match opts.debugging_opts.sanitizer {
|
||||
// Some sanitizer use lifetime intrinsics. When they are in use,
|
||||
// emit lifetime intrinsics regardless of optimization level.
|
||||
Some(Sanitizer::Address | Sanitizer::Memory) => true,
|
||||
_ => opts.optimize != config::OptLevel::No,
|
||||
};
|
||||
if !emit {
|
||||
if !self.cx().sess().emit_lifetime_markers() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2000,6 +2000,7 @@ extern "C" {
|
||||
SLPVectorize: bool,
|
||||
LoopVectorize: bool,
|
||||
DisableSimplifyLibCalls: bool,
|
||||
EmitLifetimeMarkers: bool,
|
||||
SanitizerOptions: Option<&SanitizerOptions>,
|
||||
PGOGenPath: *const c_char,
|
||||
PGOUsePath: *const c_char,
|
||||
|
@ -1179,6 +1179,28 @@ fn add_pre_link_args(
|
||||
cmd.args(&sess.opts.debugging_opts.pre_link_args);
|
||||
}
|
||||
|
||||
/// Add a link script embedded in the target, if applicable.
|
||||
fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_type: CrateType) {
|
||||
match (crate_type, &sess.target.target.options.link_script) {
|
||||
(CrateType::Cdylib | CrateType::Executable, Some(script)) => {
|
||||
if !sess.target.target.options.linker_is_gnu {
|
||||
sess.fatal("can only use link script when linking with GNU-like linker");
|
||||
}
|
||||
|
||||
let file_name = ["rustc", &sess.target.target.llvm_target, "linkfile.ld"].join("-");
|
||||
|
||||
let path = tmpdir.join(file_name);
|
||||
if let Err(e) = fs::write(&path, script) {
|
||||
sess.fatal(&format!("failed to write link script to {}: {}", path.display(), e));
|
||||
}
|
||||
|
||||
cmd.arg("--script");
|
||||
cmd.arg(path);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add arbitrary "user defined" args defined from command line and by `#[link_args]` attributes.
|
||||
/// FIXME: Determine where exactly these args need to be inserted.
|
||||
fn add_user_defined_link_args(
|
||||
@ -1421,8 +1443,11 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
|
||||
// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
|
||||
add_pre_link_args(cmd, sess, flavor, crate_type);
|
||||
|
||||
// NO-OPT-OUT
|
||||
add_link_script(cmd, sess, tmpdir, crate_type);
|
||||
|
||||
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
|
||||
if sess.target.target.options.is_like_fuchsia {
|
||||
if sess.target.target.options.is_like_fuchsia && crate_type == CrateType::Executable {
|
||||
let prefix = match sess.opts.debugging_opts.sanitizer {
|
||||
Some(Sanitizer::Address) => "asan/",
|
||||
_ => "",
|
||||
|
@ -21,7 +21,7 @@ use rustc_errors::{DiagnosticId, FatalError, Handler, Level};
|
||||
use rustc_fs_util::link_or_copy;
|
||||
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
|
||||
use rustc_incremental::{
|
||||
copy_cgu_workproducts_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
|
||||
copy_cgu_workproduct_to_incr_comp_cache_dir, in_incr_comp_dir, in_incr_comp_dir_sess,
|
||||
};
|
||||
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
|
||||
use rustc_middle::middle::cstore::EncodedMetadata;
|
||||
@ -110,6 +110,7 @@ pub struct ModuleConfig {
|
||||
pub merge_functions: bool,
|
||||
pub inline_threshold: Option<usize>,
|
||||
pub new_llvm_pass_manager: bool,
|
||||
pub emit_lifetime_markers: bool,
|
||||
}
|
||||
|
||||
impl ModuleConfig {
|
||||
@ -244,6 +245,7 @@ impl ModuleConfig {
|
||||
|
||||
inline_threshold: sess.opts.cg.inline_threshold,
|
||||
new_llvm_pass_manager: sess.opts.debugging_opts.new_llvm_pass_manager,
|
||||
emit_lifetime_markers: sess.emit_lifetime_markers(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -465,17 +467,13 @@ fn copy_all_cgu_workproducts_to_incr_comp_cache_dir(
|
||||
return work_products;
|
||||
}
|
||||
|
||||
let _timer = sess.timer("incr_comp_copy_cgu_workproducts");
|
||||
let _timer = sess.timer("copy_all_cgu_workproducts_to_incr_comp_cache_dir");
|
||||
|
||||
for module in compiled_modules.modules.iter().filter(|m| m.kind == ModuleKind::Regular) {
|
||||
let mut files = vec![];
|
||||
|
||||
if let Some(ref path) = module.object {
|
||||
files.push(path.clone());
|
||||
}
|
||||
let path = module.object.as_ref().map(|path| path.clone());
|
||||
|
||||
if let Some((id, product)) =
|
||||
copy_cgu_workproducts_to_incr_comp_cache_dir(sess, &module.name, &files)
|
||||
copy_cgu_workproduct_to_incr_comp_cache_dir(sess, &module.name, &path)
|
||||
{
|
||||
work_products.insert(id, product);
|
||||
}
|
||||
@ -817,7 +815,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
|
||||
) -> Result<WorkItemResult<B>, FatalError> {
|
||||
let incr_comp_session_dir = cgcx.incr_comp_session_dir.as_ref().unwrap();
|
||||
let mut object = None;
|
||||
for saved_file in &module.source.saved_files {
|
||||
if let Some(saved_file) = module.source.saved_file {
|
||||
let obj_out = cgcx.output_filenames.temp_path(OutputType::Object, Some(&module.name));
|
||||
object = Some(obj_out.clone());
|
||||
let source_file = in_incr_comp_dir(&incr_comp_session_dir, &saved_file);
|
||||
|
@ -198,7 +198,6 @@ pub fn push_debuginfo_type_name<'tcx>(
|
||||
ty::Error
|
||||
| ty::Infer(_)
|
||||
| ty::Placeholder(..)
|
||||
| ty::UnnormalizedProjection(..)
|
||||
| ty::Projection(..)
|
||||
| ty::Bound(..)
|
||||
| ty::Opaque(..)
|
||||
|
@ -28,7 +28,7 @@ rustc_index = { path = "../librustc_index", package = "rustc_index" }
|
||||
bitflags = "1.2.1"
|
||||
measureme = "0.7.1"
|
||||
libc = "0.2"
|
||||
stacker = "0.1.6"
|
||||
stacker = "0.1.9"
|
||||
|
||||
[dependencies.parking_lot]
|
||||
version = "0.10"
|
||||
|
@ -12,7 +12,7 @@
|
||||
#![feature(generators)]
|
||||
#![feature(generator_trait)]
|
||||
#![feature(fn_traits)]
|
||||
#![feature(specialization)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(nll)]
|
||||
#![feature(allow_internal_unstable)]
|
||||
|
@ -52,7 +52,7 @@ impl<T: PartialEq> TinyList<T> {
|
||||
if &e.data == data {
|
||||
return true;
|
||||
}
|
||||
elem = e.next.as_ref().map(|e| &**e);
|
||||
elem = e.next.as_deref();
|
||||
}
|
||||
false
|
||||
}
|
||||
@ -62,7 +62,7 @@ impl<T: PartialEq> TinyList<T> {
|
||||
let (mut elem, mut count) = (self.head.as_ref(), 0);
|
||||
while let Some(ref e) = elem {
|
||||
count += 1;
|
||||
elem = e.next.as_ref().map(|e| &**e);
|
||||
elem = e.next.as_deref();
|
||||
}
|
||||
count
|
||||
}
|
||||
|
@ -1138,6 +1138,16 @@ pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorReported>
|
||||
})
|
||||
}
|
||||
|
||||
/// Variant of `catch_fatal_errors` for the `interface::Result` return type
|
||||
/// that also computes the exit code.
|
||||
pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
|
||||
let result = catch_fatal_errors(f).and_then(|result| result);
|
||||
match result {
|
||||
Ok(()) => EXIT_SUCCESS,
|
||||
Err(_) => EXIT_FAILURE,
|
||||
}
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
static ref DEFAULT_HOOK: Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static> = {
|
||||
let hook = panic::take_hook();
|
||||
@ -1228,12 +1238,12 @@ pub fn init_rustc_env_logger() {
|
||||
env_logger::init_from_env("RUSTC_LOG");
|
||||
}
|
||||
|
||||
pub fn main() {
|
||||
pub fn main() -> ! {
|
||||
let start = Instant::now();
|
||||
init_rustc_env_logger();
|
||||
let mut callbacks = TimePassesCallbacks::default();
|
||||
install_ice_hook();
|
||||
let result = catch_fatal_errors(|| {
|
||||
let exit_code = catch_with_exit_code(|| {
|
||||
let args = env::args_os()
|
||||
.enumerate()
|
||||
.map(|(i, arg)| {
|
||||
@ -1246,13 +1256,8 @@ pub fn main() {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
run_compiler(&args, &mut callbacks, None, None)
|
||||
})
|
||||
.and_then(|result| result);
|
||||
let exit_code = match result {
|
||||
Ok(_) => EXIT_SUCCESS,
|
||||
Err(_) => EXIT_FAILURE,
|
||||
};
|
||||
});
|
||||
// The extra `\t` is necessary to align this label with the others.
|
||||
print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed());
|
||||
process::exit(exit_code);
|
||||
process::exit(exit_code)
|
||||
}
|
||||
|
@ -120,6 +120,7 @@ E0223: include_str!("./error_codes/E0223.md"),
|
||||
E0224: include_str!("./error_codes/E0224.md"),
|
||||
E0225: include_str!("./error_codes/E0225.md"),
|
||||
E0226: include_str!("./error_codes/E0226.md"),
|
||||
E0228: include_str!("./error_codes/E0228.md"),
|
||||
E0229: include_str!("./error_codes/E0229.md"),
|
||||
E0230: include_str!("./error_codes/E0230.md"),
|
||||
E0231: include_str!("./error_codes/E0231.md"),
|
||||
@ -435,6 +436,7 @@ E0750: include_str!("./error_codes/E0750.md"),
|
||||
E0751: include_str!("./error_codes/E0751.md"),
|
||||
E0752: include_str!("./error_codes/E0752.md"),
|
||||
E0753: include_str!("./error_codes/E0753.md"),
|
||||
E0754: include_str!("./error_codes/E0754.md"),
|
||||
E0755: include_str!("./error_codes/E0755.md"),
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
@ -483,7 +485,6 @@ E0755: include_str!("./error_codes/E0755.md"),
|
||||
// E0218, // no associated type defined
|
||||
// E0219, // associated type defined in higher-ranked supertrait
|
||||
E0227, // ambiguous lifetime bound, explicit lifetime bound required
|
||||
E0228, // explicit lifetime bound required
|
||||
// E0233,
|
||||
// E0234,
|
||||
// E0235, // structure constructor specifies a structure of type but
|
||||
|
40
src/librustc_error_codes/error_codes/E0228.md
Normal file
40
src/librustc_error_codes/error_codes/E0228.md
Normal file
@ -0,0 +1,40 @@
|
||||
The lifetime bound for this object type cannot be deduced from context and must
|
||||
be specified.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0228
|
||||
trait Trait { }
|
||||
|
||||
struct TwoBounds<'a, 'b, T: Sized + 'a + 'b> {
|
||||
x: &'a i32,
|
||||
y: &'b i32,
|
||||
z: T,
|
||||
}
|
||||
|
||||
type Foo<'a, 'b> = TwoBounds<'a, 'b, dyn Trait>;
|
||||
```
|
||||
|
||||
When a trait object is used as a type argument of a generic type, Rust will try
|
||||
to infer its lifetime if unspecified. However, this isn't possible when the
|
||||
containing type has more than one lifetime bound.
|
||||
|
||||
The above example can be resolved by either reducing the number of lifetime
|
||||
bounds to one or by making the trait object lifetime explicit, like so:
|
||||
|
||||
```
|
||||
trait Trait { }
|
||||
|
||||
struct TwoBounds<'a, 'b, T: Sized + 'a + 'b> {
|
||||
x: &'a i32,
|
||||
y: &'b i32,
|
||||
z: T,
|
||||
}
|
||||
|
||||
type Foo<'a, 'b> = TwoBounds<'a, 'b, dyn Trait + 'b>;
|
||||
```
|
||||
|
||||
For more information, see [RFC 599] and its amendment [RFC 1156].
|
||||
|
||||
[RFC 599]: https://github.com/rust-lang/rfcs/blob/master/text/0599-default-object-bound.md
|
||||
[RFC 1156]: https://github.com/rust-lang/rfcs/blob/master/text/1156-adjust-default-object-bounds.md
|
@ -64,7 +64,7 @@ impl Trait for Foo {
|
||||
}
|
||||
```
|
||||
|
||||
The nightly feature [Arbintrary self types][AST] extends the accepted
|
||||
The nightly feature [Arbitrary self types][AST] extends the accepted
|
||||
set of receiver types to also include any type that can dereference to
|
||||
`Self`:
|
||||
|
||||
|
@ -7,7 +7,7 @@ Example of erroneous code:
|
||||
# fn satisfied(n: usize) -> bool { n % 23 == 0 }
|
||||
let result = while true {
|
||||
if satisfied(i) {
|
||||
break 2*i; // error: `break` with value from a `while` loop
|
||||
break 2 * i; // error: `break` with value from a `while` loop
|
||||
}
|
||||
i += 1;
|
||||
};
|
||||
@ -22,9 +22,9 @@ Make sure `break value;` statements only occur in `loop` loops:
|
||||
```
|
||||
# let mut i = 1;
|
||||
# fn satisfied(n: usize) -> bool { n % 23 == 0 }
|
||||
let result = loop { // ok!
|
||||
let result = loop { // This is now a "loop" loop.
|
||||
if satisfied(i) {
|
||||
break 2*i;
|
||||
break 2 * i; // ok!
|
||||
}
|
||||
i += 1;
|
||||
};
|
||||
|
@ -1,7 +1,4 @@
|
||||
When matching against an exclusive range, the compiler verifies that the range
|
||||
is non-empty. Exclusive range patterns include the start point but not the end
|
||||
point, so this is equivalent to requiring the start of the range to be less
|
||||
than the end of the range.
|
||||
A lower range wasn't less than the upper range.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
@ -17,3 +14,8 @@ fn main() {
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
When matching against an exclusive range, the compiler verifies that the range
|
||||
is non-empty. Exclusive range patterns include the start point but not the end
|
||||
point, so this is equivalent to requiring the start of the range to be less
|
||||
than the end of the range.
|
||||
|
@ -1,4 +1,4 @@
|
||||
In a `fn` type, a lifetime appears only in the return type,
|
||||
In a `fn` type, a lifetime appears only in the return type
|
||||
and not in the arguments types.
|
||||
|
||||
Erroneous code example:
|
||||
@ -10,8 +10,11 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
To fix this issue, either use the lifetime in the arguments, or use
|
||||
`'static`. Example:
|
||||
The problem here is that the lifetime isn't contrained by any of the arguments,
|
||||
making it impossible to determine how long it's supposed to live.
|
||||
|
||||
To fix this issue, either use the lifetime in the arguments, or use the
|
||||
`'static` lifetime. Example:
|
||||
|
||||
```
|
||||
fn main() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
A lifetime appears only in an associated-type binding,
|
||||
and not in the input types to the trait.
|
||||
A lifetime is only present in an associated-type binding, and not in the input
|
||||
types to the trait.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
The value of `N` that was specified for `repr(align(N))` was not a power
|
||||
of two, or was greater than 2^29.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0589
|
||||
#[repr(align(15))] // error: invalid `repr(align)` attribute: not a power of two
|
||||
enum Foo {
|
||||
|
33
src/librustc_error_codes/error_codes/E0754.md
Normal file
33
src/librustc_error_codes/error_codes/E0754.md
Normal file
@ -0,0 +1,33 @@
|
||||
An non-ascii identifier was used in an invalid context.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0754
|
||||
# #![feature(non_ascii_idents)]
|
||||
|
||||
mod řųśť;
|
||||
// ^ error!
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
```compile_fail,E0754
|
||||
# #![feature(non_ascii_idents)]
|
||||
|
||||
#[no_mangle]
|
||||
fn řųśť() {}
|
||||
// ^ error!
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
Non-ascii can be used as module names if it is inline
|
||||
or a #\[path\] attribute is specified. For example:
|
||||
|
||||
```
|
||||
# #![feature(non_ascii_idents)]
|
||||
|
||||
mod řųśť {
|
||||
const IS_GREAT: bool = true;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
@ -3,7 +3,7 @@ or `Self` that references lifetimes from a parent scope.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0754,edition2018
|
||||
```compile_fail,E0755,edition2018
|
||||
struct S<'a>(&'a i32);
|
||||
|
||||
impl<'a> S<'a> {
|
||||
|
@ -50,13 +50,13 @@ fn t1() {
|
||||
assert_eq!(string_reader.next_token(), token::Whitespace);
|
||||
// Read another token.
|
||||
let tok3 = string_reader.next_token();
|
||||
assert_eq!(string_reader.pos.clone(), BytePos(28));
|
||||
assert_eq!(string_reader.pos(), BytePos(28));
|
||||
let tok4 = Token::new(mk_ident("main"), Span::with_root_ctxt(BytePos(24), BytePos(28)));
|
||||
assert_eq!(tok3.kind, tok4.kind);
|
||||
assert_eq!(tok3.span, tok4.span);
|
||||
|
||||
assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren));
|
||||
assert_eq!(string_reader.pos.clone(), BytePos(29))
|
||||
assert_eq!(string_reader.pos(), BytePos(29))
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -507,9 +507,14 @@ impl server::Ident for Rustc<'_> {
|
||||
}
|
||||
|
||||
impl server::Literal for Rustc<'_> {
|
||||
// FIXME(eddyb) `Literal` should not expose internal `Debug` impls.
|
||||
fn debug(&mut self, literal: &Self::Literal) -> String {
|
||||
format!("{:?}", literal)
|
||||
fn debug_kind(&mut self, literal: &Self::Literal) -> String {
|
||||
format!("{:?}", literal.lit.kind)
|
||||
}
|
||||
fn symbol(&mut self, literal: &Self::Literal) -> String {
|
||||
literal.lit.symbol.to_string()
|
||||
}
|
||||
fn suffix(&mut self, literal: &Self::Literal) -> Option<String> {
|
||||
literal.lit.suffix.as_ref().map(Symbol::to_string)
|
||||
}
|
||||
fn integer(&mut self, n: &str) -> Self::Literal {
|
||||
self.lit(token::Integer, Symbol::intern(n), None)
|
||||
|
@ -8,7 +8,7 @@
|
||||
#![feature(const_panic)]
|
||||
#![feature(in_band_lifetimes)]
|
||||
#![feature(or_patterns)]
|
||||
#![feature(specialization)]
|
||||
#![feature(min_specialization)]
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
#[macro_use]
|
||||
|
@ -15,7 +15,7 @@ pub mod assert_module_sources;
|
||||
mod persist;
|
||||
|
||||
pub use assert_dep_graph::assert_dep_graph;
|
||||
pub use persist::copy_cgu_workproducts_to_incr_comp_cache_dir;
|
||||
pub use persist::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
||||
pub use persist::delete_workproduct_files;
|
||||
pub use persist::dep_graph_tcx_init;
|
||||
pub use persist::finalize_session_directory;
|
||||
|
@ -134,7 +134,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
|
||||
|
||||
for swp in work_products {
|
||||
let mut all_files_exist = true;
|
||||
for file_name in swp.work_product.saved_files.iter() {
|
||||
if let Some(ref file_name) = swp.work_product.saved_file {
|
||||
let path = in_incr_comp_dir_sess(sess, file_name);
|
||||
if !path.exists() {
|
||||
all_files_exist = false;
|
||||
|
@ -21,5 +21,5 @@ pub use load::LoadResult;
|
||||
pub use load::{load_dep_graph, DepGraphFuture};
|
||||
pub use save::save_dep_graph;
|
||||
pub use save::save_work_product_index;
|
||||
pub use work_product::copy_cgu_workproducts_to_incr_comp_cache_dir;
|
||||
pub use work_product::copy_cgu_workproduct_to_incr_comp_cache_dir;
|
||||
pub use work_product::delete_workproduct_files;
|
||||
|
@ -74,9 +74,9 @@ pub fn save_work_product_index(
|
||||
if !new_work_products.contains_key(id) {
|
||||
work_product::delete_workproduct_files(sess, wp);
|
||||
debug_assert!(
|
||||
wp.saved_files
|
||||
.iter()
|
||||
.all(|file_name| { !in_incr_comp_dir_sess(sess, file_name).exists() })
|
||||
wp.saved_file.as_ref().map_or(true, |file_name| {
|
||||
!in_incr_comp_dir_sess(sess, &file_name).exists()
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -85,7 +85,7 @@ pub fn save_work_product_index(
|
||||
debug_assert!({
|
||||
new_work_products
|
||||
.iter()
|
||||
.flat_map(|(_, wp)| wp.saved_files.iter())
|
||||
.flat_map(|(_, wp)| wp.saved_file.iter())
|
||||
.map(|name| in_incr_comp_dir_sess(sess, name))
|
||||
.all(|path| path.exists())
|
||||
});
|
||||
|
@ -7,43 +7,41 @@ use rustc_session::Session;
|
||||
use std::fs as std_fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub fn copy_cgu_workproducts_to_incr_comp_cache_dir(
|
||||
pub fn copy_cgu_workproduct_to_incr_comp_cache_dir(
|
||||
sess: &Session,
|
||||
cgu_name: &str,
|
||||
files: &[PathBuf],
|
||||
path: &Option<PathBuf>,
|
||||
) -> Option<(WorkProductId, WorkProduct)> {
|
||||
debug!("copy_cgu_workproducts_to_incr_comp_cache_dir({:?},{:?})", cgu_name, files);
|
||||
debug!("copy_cgu_workproduct_to_incr_comp_cache_dir({:?},{:?})", cgu_name, path);
|
||||
sess.opts.incremental.as_ref()?;
|
||||
|
||||
let saved_files = files
|
||||
.iter()
|
||||
.map(|path| {
|
||||
let file_name = format!("{}.o", cgu_name);
|
||||
let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
|
||||
match link_or_copy(path, &path_in_incr_dir) {
|
||||
Ok(_) => Some(file_name),
|
||||
Err(err) => {
|
||||
sess.warn(&format!(
|
||||
"error copying object file `{}` \
|
||||
to incremental directory as `{}`: {}",
|
||||
path.display(),
|
||||
path_in_incr_dir.display(),
|
||||
err
|
||||
));
|
||||
None
|
||||
}
|
||||
let saved_file = if let Some(path) = path {
|
||||
let file_name = format!("{}.o", cgu_name);
|
||||
let path_in_incr_dir = in_incr_comp_dir_sess(sess, &file_name);
|
||||
match link_or_copy(path, &path_in_incr_dir) {
|
||||
Ok(_) => Some(file_name),
|
||||
Err(err) => {
|
||||
sess.warn(&format!(
|
||||
"error copying object file `{}` to incremental directory as `{}`: {}",
|
||||
path.display(),
|
||||
path_in_incr_dir.display(),
|
||||
err
|
||||
));
|
||||
return None;
|
||||
}
|
||||
})
|
||||
.collect::<Option<Vec<_>>>()?;
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_files };
|
||||
let work_product = WorkProduct { cgu_name: cgu_name.to_string(), saved_file };
|
||||
|
||||
let work_product_id = WorkProductId::from_cgu_name(cgu_name);
|
||||
Some((work_product_id, work_product))
|
||||
}
|
||||
|
||||
pub fn delete_workproduct_files(sess: &Session, work_product: &WorkProduct) {
|
||||
for file_name in &work_product.saved_files {
|
||||
if let Some(ref file_name) = work_product.saved_file {
|
||||
let path = in_incr_comp_dir_sess(sess, file_name);
|
||||
match std_fs::remove_file(&path) {
|
||||
Ok(()) => {}
|
||||
|
@ -65,7 +65,7 @@ impl Idx for u32 {
|
||||
/// `u32::MAX`. You can also customize things like the `Debug` impl,
|
||||
/// what traits are derived, and so forth via the macro.
|
||||
#[macro_export]
|
||||
#[allow_internal_unstable(step_trait, rustc_attrs)]
|
||||
#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)]
|
||||
macro_rules! newtype_index {
|
||||
// ---- public rules ----
|
||||
|
||||
@ -181,7 +181,7 @@ macro_rules! newtype_index {
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::iter::Step for $type {
|
||||
unsafe impl ::std::iter::Step for $type {
|
||||
#[inline]
|
||||
fn steps_between(start: &Self, end: &Self) -> Option<usize> {
|
||||
<usize as ::std::iter::Step>::steps_between(
|
||||
@ -191,33 +191,13 @@ macro_rules! newtype_index {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn replace_one(&mut self) -> Self {
|
||||
::std::mem::replace(self, Self::from_u32(1))
|
||||
fn forward_checked(start: Self, u: usize) -> Option<Self> {
|
||||
Self::index(start).checked_add(u).map(Self::from_usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn replace_zero(&mut self) -> Self {
|
||||
::std::mem::replace(self, Self::from_u32(0))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_one(&self) -> Self {
|
||||
Self::from_usize(Self::index(*self) + 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sub_one(&self) -> Self {
|
||||
Self::from_usize(Self::index(*self) - 1)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_usize(&self, u: usize) -> Option<Self> {
|
||||
Self::index(*self).checked_add(u).map(Self::from_usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn sub_usize(&self, u: usize) -> Option<Self> {
|
||||
Self::index(*self).checked_sub(u).map(Self::from_usize)
|
||||
fn backward_checked(start: Self, u: usize) -> Option<Self> {
|
||||
Self::index(start).checked_sub(u).map(Self::from_usize)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -415,7 +415,6 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> {
|
||||
| ty::Never
|
||||
| ty::Tuple(..)
|
||||
| ty::Projection(..)
|
||||
| ty::UnnormalizedProjection(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Param(..)
|
||||
| ty::Opaque(..) => {
|
||||
|
@ -554,7 +554,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
|
||||
let output = bound_output.skip_binder();
|
||||
err.span_label(e.span, &format!("this method call resolves to `{:?}`", output));
|
||||
let kind = &output.kind;
|
||||
if let ty::Projection(proj) | ty::UnnormalizedProjection(proj) = kind {
|
||||
if let ty::Projection(proj) = kind {
|
||||
if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) {
|
||||
err.span_label(span, &format!("`{:?}` defined here", output));
|
||||
}
|
||||
|
@ -204,7 +204,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> {
|
||||
| ty::Never
|
||||
| ty::Tuple(..)
|
||||
| ty::Projection(..)
|
||||
| ty::UnnormalizedProjection(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Param(..)
|
||||
| ty::Closure(..)
|
||||
|
@ -325,8 +325,21 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
debug!("enforce_member_constraint: final least choice = {:?}", least_choice);
|
||||
if least_choice != member_lower_bound {
|
||||
// (#72087) Different `ty::Regions` can be known to be equal, for
|
||||
// example, we know that `'a` and `'static` are equal in a function
|
||||
// with a parameter of type `&'static &'a ()`.
|
||||
//
|
||||
// When we have two equal regions like this `expansion` will use
|
||||
// `lub_concrete_regions` to pick a canonical representative. The same
|
||||
// choice is needed here so that we don't end up in a cycle of
|
||||
// `expansion` changing the region one way and the code here changing
|
||||
// it back.
|
||||
let lub = self.lub_concrete_regions(least_choice, member_lower_bound);
|
||||
debug!(
|
||||
"enforce_member_constraint: final least choice = {:?}\nlub = {:?}",
|
||||
least_choice, lub
|
||||
);
|
||||
if lub != member_lower_bound {
|
||||
*var_values.value_mut(member_vid) = VarValue::Value(least_choice);
|
||||
true
|
||||
} else {
|
||||
@ -578,8 +591,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
|
||||
self.tcx().mk_region(ReScope(lub))
|
||||
}
|
||||
|
||||
(&ReEarlyBound(_), &ReEarlyBound(_) | &ReFree(_))
|
||||
| (&ReFree(_), &ReEarlyBound(_) | &ReFree(_)) => {
|
||||
(&ReEarlyBound(_) | &ReFree(_), &ReEarlyBound(_) | &ReFree(_)) => {
|
||||
self.region_rels.lub_free_regions(a, b)
|
||||
}
|
||||
|
||||
|
@ -112,8 +112,7 @@ pub fn elaborate_predicates<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
predicates: impl Iterator<Item = ty::Predicate<'tcx>>,
|
||||
) -> Elaborator<'tcx> {
|
||||
let obligations =
|
||||
predicates.into_iter().map(|predicate| predicate_obligation(predicate, None)).collect();
|
||||
let obligations = predicates.map(|predicate| predicate_obligation(predicate, None)).collect();
|
||||
elaborate_obligations(tcx, obligations)
|
||||
}
|
||||
|
||||
@ -149,7 +148,7 @@ impl Elaborator<'tcx> {
|
||||
// Get predicates declared on the trait.
|
||||
let predicates = tcx.super_predicates_of(data.def_id());
|
||||
|
||||
let obligations = predicates.predicates.into_iter().map(|(pred, span)| {
|
||||
let obligations = predicates.predicates.iter().map(|(pred, span)| {
|
||||
predicate_obligation(
|
||||
pred.subst_supertrait(tcx, &data.to_poly_trait_ref()),
|
||||
Some(*span),
|
||||
|
@ -137,7 +137,7 @@ impl<'tcx> Queries<'tcx> {
|
||||
let result = passes::register_plugins(
|
||||
self.session(),
|
||||
&*self.codegen_backend().metadata_loader(),
|
||||
self.compiler.register_lints.as_ref().map(|p| &**p).unwrap_or_else(|| empty),
|
||||
self.compiler.register_lints.as_deref().unwrap_or_else(|| empty),
|
||||
krate,
|
||||
&crate_name,
|
||||
);
|
||||
|
@ -1,5 +1,11 @@
|
||||
//! Low-level Rust lexer.
|
||||
//!
|
||||
//! The idea with `librustc_lexer` is to make a reusable library,
|
||||
//! by separating out pure lexing and rustc-specific concerns, like spans,
|
||||
//! error reporting an interning. So, rustc_lexer operates directly on `&str`,
|
||||
//! produces simple tokens which are a pair of type-tag and a bit of original text,
|
||||
//! and does not report errors, instead storing them as flags on the token.
|
||||
//!
|
||||
//! Tokens produced by this lexer are not yet ready for parsing the Rust syntax,
|
||||
//! for that see `librustc_parse::lexer`, which converts this basic token stream
|
||||
//! into wide tokens used by actual parser.
|
||||
@ -719,6 +725,9 @@ impl Cursor<'_> {
|
||||
|
||||
// Check that amount of closing '#' symbols
|
||||
// is equal to the amount of opening ones.
|
||||
// Note that this will not consume extra trailing `#` characters:
|
||||
// `r###"abcde"####` is lexed as a `LexedRawString { n_hashes: 3 }`
|
||||
// followed by a `#` token.
|
||||
let mut hashes_left = n_start_hashes;
|
||||
let is_closing_hash = |c| {
|
||||
if c == '#' && hashes_left != 0 {
|
||||
@ -739,8 +748,8 @@ impl Cursor<'_> {
|
||||
possible_terminator_offset: None,
|
||||
};
|
||||
} else if n_end_hashes > max_hashes {
|
||||
// Keep track of possible terminators to give a hint about where there might be
|
||||
// a missing terminator
|
||||
// Keep track of possible terminators to give a hint about
|
||||
// where there might be a missing terminator
|
||||
possible_terminator_offset =
|
||||
Some(self.len_consumed() - start_pos - n_end_hashes + prefix_len);
|
||||
max_hashes = n_end_hashes;
|
||||
|
@ -58,6 +58,42 @@ pub enum EscapeError {
|
||||
NonAsciiCharInByteString,
|
||||
}
|
||||
|
||||
/// Takes a contents of a literal (without quotes) and produces a
|
||||
/// sequence of escaped characters or errors.
|
||||
/// Values are returned through invoking of the provided callback.
|
||||
pub fn unescape_literal<F>(literal_text: &str, mode: Mode, callback: &mut F)
|
||||
where
|
||||
F: FnMut(Range<usize>, Result<char, EscapeError>),
|
||||
{
|
||||
match mode {
|
||||
Mode::Char | Mode::Byte => {
|
||||
let mut chars = literal_text.chars();
|
||||
let result = unescape_char_or_byte(&mut chars, mode);
|
||||
// The Chars iterator moved forward.
|
||||
callback(0..(literal_text.len() - chars.as_str().len()), result);
|
||||
}
|
||||
Mode::Str | Mode::ByteStr => unescape_str_or_byte_str(literal_text, mode, callback),
|
||||
// NOTE: Raw strings do not perform any explicit character escaping, here we
|
||||
// only translate CRLF to LF and produce errors on bare CR.
|
||||
Mode::RawStr | Mode::RawByteStr => {
|
||||
unescape_raw_str_or_byte_str(literal_text, mode, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes a contents of a byte, byte string or raw byte string (without quotes)
|
||||
/// and produces a sequence of bytes or errors.
|
||||
/// Values are returned through invoking of the provided callback.
|
||||
pub fn unescape_byte_literal<F>(literal_text: &str, mode: Mode, callback: &mut F)
|
||||
where
|
||||
F: FnMut(Range<usize>, Result<u8, EscapeError>),
|
||||
{
|
||||
assert!(mode.is_bytes());
|
||||
unescape_literal(literal_text, mode, &mut |range, result| {
|
||||
callback(range, result.map(byte_from_char));
|
||||
})
|
||||
}
|
||||
|
||||
/// Takes a contents of a char literal (without quotes), and returns an
|
||||
/// unescaped char or an error
|
||||
pub fn unescape_char(literal_text: &str) -> Result<char, (usize, EscapeError)> {
|
||||
@ -75,54 +111,6 @@ pub fn unescape_byte(literal_text: &str) -> Result<u8, (usize, EscapeError)> {
|
||||
.map_err(|err| (literal_text.len() - chars.as_str().len(), err))
|
||||
}
|
||||
|
||||
/// Takes a contents of a string literal (without quotes) and produces a
|
||||
/// sequence of escaped characters or errors.
|
||||
/// Values are returned through invoking of the provided callback.
|
||||
pub fn unescape_str<F>(literal_text: &str, callback: &mut F)
|
||||
where
|
||||
F: FnMut(Range<usize>, Result<char, EscapeError>),
|
||||
{
|
||||
unescape_str_or_byte_str(literal_text, Mode::Str, callback)
|
||||
}
|
||||
|
||||
/// Takes a contents of a byte string literal (without quotes) and produces a
|
||||
/// sequence of bytes or errors.
|
||||
/// Values are returned through invoking of the provided callback.
|
||||
pub fn unescape_byte_str<F>(literal_text: &str, callback: &mut F)
|
||||
where
|
||||
F: FnMut(Range<usize>, Result<u8, EscapeError>),
|
||||
{
|
||||
unescape_str_or_byte_str(literal_text, Mode::ByteStr, &mut |range, char| {
|
||||
callback(range, char.map(byte_from_char))
|
||||
})
|
||||
}
|
||||
|
||||
/// Takes a contents of a raw string literal (without quotes) and produces a
|
||||
/// sequence of characters or errors.
|
||||
/// Values are returned through invoking of the provided callback.
|
||||
/// NOTE: Raw strings do not perform any explicit character escaping, here we
|
||||
/// only translate CRLF to LF and produce errors on bare CR.
|
||||
pub fn unescape_raw_str<F>(literal_text: &str, callback: &mut F)
|
||||
where
|
||||
F: FnMut(Range<usize>, Result<char, EscapeError>),
|
||||
{
|
||||
unescape_raw_str_or_byte_str(literal_text, Mode::Str, callback)
|
||||
}
|
||||
|
||||
/// Takes a contents of a raw byte string literal (without quotes) and produces a
|
||||
/// sequence of bytes or errors.
|
||||
/// Values are returned through invoking of the provided callback.
|
||||
/// NOTE: Raw strings do not perform any explicit character escaping, here we
|
||||
/// only translate CRLF to LF and produce errors on bare CR.
|
||||
pub fn unescape_raw_byte_str<F>(literal_text: &str, callback: &mut F)
|
||||
where
|
||||
F: FnMut(Range<usize>, Result<u8, EscapeError>),
|
||||
{
|
||||
unescape_raw_str_or_byte_str(literal_text, Mode::ByteStr, &mut |range, char| {
|
||||
callback(range, char.map(byte_from_char))
|
||||
})
|
||||
}
|
||||
|
||||
/// What kind of literal do we parse.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Mode {
|
||||
@ -130,13 +118,15 @@ pub enum Mode {
|
||||
Str,
|
||||
Byte,
|
||||
ByteStr,
|
||||
RawStr,
|
||||
RawByteStr,
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
pub fn in_single_quotes(self) -> bool {
|
||||
match self {
|
||||
Mode::Char | Mode::Byte => true,
|
||||
Mode::Str | Mode::ByteStr => false,
|
||||
Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,8 +136,8 @@ impl Mode {
|
||||
|
||||
pub fn is_bytes(self) -> bool {
|
||||
match self {
|
||||
Mode::Byte | Mode::ByteStr => true,
|
||||
Mode::Char | Mode::Str => false,
|
||||
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
|
||||
Mode::Char | Mode::Str | Mode::RawStr => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -345,7 +335,7 @@ where
|
||||
|
||||
fn byte_from_char(c: char) -> u8 {
|
||||
let res = c as u32;
|
||||
assert!(res <= u8::max_value() as u32, "guaranteed because of Mode::Byte(Str)");
|
||||
assert!(res <= u8::max_value() as u32, "guaranteed because of Mode::ByteStr");
|
||||
res as u8
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ fn test_unescape_char_good() {
|
||||
fn test_unescape_str_good() {
|
||||
fn check(literal_text: &str, expected: &str) {
|
||||
let mut buf = Ok(String::with_capacity(literal_text.len()));
|
||||
unescape_str(literal_text, &mut |range, c| {
|
||||
unescape_literal(literal_text, Mode::Str, &mut |range, c| {
|
||||
if let Ok(b) = &mut buf {
|
||||
match c {
|
||||
Ok(c) => b.push(c),
|
||||
@ -222,7 +222,7 @@ fn test_unescape_byte_good() {
|
||||
fn test_unescape_byte_str_good() {
|
||||
fn check(literal_text: &str, expected: &[u8]) {
|
||||
let mut buf = Ok(Vec::with_capacity(literal_text.len()));
|
||||
unescape_byte_str(literal_text, &mut |range, c| {
|
||||
unescape_byte_literal(literal_text, Mode::ByteStr, &mut |range, c| {
|
||||
if let Ok(b) = &mut buf {
|
||||
match c {
|
||||
Ok(c) => b.push(c),
|
||||
@ -246,7 +246,7 @@ fn test_unescape_byte_str_good() {
|
||||
fn test_unescape_raw_str() {
|
||||
fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)]) {
|
||||
let mut unescaped = Vec::with_capacity(literal.len());
|
||||
unescape_raw_str(literal, &mut |range, res| unescaped.push((range, res)));
|
||||
unescape_literal(literal, Mode::RawStr, &mut |range, res| unescaped.push((range, res)));
|
||||
assert_eq!(unescaped, expected);
|
||||
}
|
||||
|
||||
@ -258,7 +258,9 @@ fn test_unescape_raw_str() {
|
||||
fn test_unescape_raw_byte_str() {
|
||||
fn check(literal: &str, expected: &[(Range<usize>, Result<u8, EscapeError>)]) {
|
||||
let mut unescaped = Vec::with_capacity(literal.len());
|
||||
unescape_raw_byte_str(literal, &mut |range, res| unescaped.push((range, res)));
|
||||
unescape_byte_literal(literal, Mode::RawByteStr, &mut |range, res| {
|
||||
unescaped.push((range, res))
|
||||
});
|
||||
assert_eq!(unescaped, expected);
|
||||
}
|
||||
|
||||
|
@ -28,8 +28,8 @@ use rustc_ast::visit::{FnCtxt, FnKind};
|
||||
use rustc_ast_pretty::pprust::{self, expr_to_string};
|
||||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_errors::{Applicability, DiagnosticBuilder};
|
||||
use rustc_feature::Stability;
|
||||
use rustc_feature::{deprecated_attributes, AttributeGate, AttributeTemplate, AttributeType};
|
||||
use rustc_feature::{GateIssue, Stability};
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def_id::DefId;
|
||||
@ -1817,13 +1817,21 @@ impl EarlyLintPass for IncompleteFeatures {
|
||||
.map(|(name, span, _)| (name, span))
|
||||
.chain(features.declared_lib_features.iter().map(|(name, span)| (name, span)))
|
||||
.filter(|(name, _)| rustc_feature::INCOMPLETE_FEATURES.iter().any(|f| name == &f))
|
||||
.for_each(|(name, &span)| {
|
||||
.for_each(|(&name, &span)| {
|
||||
cx.struct_span_lint(INCOMPLETE_FEATURES, span, |lint| {
|
||||
lint.build(&format!(
|
||||
"the feature `{}` is incomplete and may cause the compiler to crash",
|
||||
let mut builder = lint.build(&format!(
|
||||
"the feature `{}` is incomplete and may not be safe to use \
|
||||
and/or cause compiler crashes",
|
||||
name,
|
||||
))
|
||||
.emit()
|
||||
));
|
||||
if let Some(n) = rustc_feature::find_feature_issue(name, GateIssue::Language) {
|
||||
builder.note(&format!(
|
||||
"see issue #{} <https://github.com/rust-lang/rust/issues/{}> \
|
||||
for more information",
|
||||
n, n,
|
||||
));
|
||||
}
|
||||
builder.emit();
|
||||
})
|
||||
});
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user