Auto merge of #54168 - kennytm:rollup, r=kennytm
Rollup of 11 pull requests Successful merges: - #53371 (Do not emit E0277 on incorrect tuple destructured binding) - #53829 (Add rustc SHA to released DWARF debuginfo) - #53950 (Allow for opting out of ThinLTO and clean up LTO related cli flag handling.) - #53976 (Replace unwrap calls in example by expect) - #54070 (Add Error::description soft-deprecation to RELEASES) - #54076 (miri loop detector hashing) - #54119 (Add some unit tests for find_best_match_for_name) - #54147 (Add a test that tries to modify static memory at compile-time) - #54150 (Updated 1.29 release notes with --document-private-items flag) - #54163 (Update stage 0 to latest beta) - #54170 (COMPILER_TESTS.md has been moved)
This commit is contained in:
@@ -368,8 +368,7 @@ will run all the tests on every platform we support. If it all works out,
|
|||||||
[merge-queue]: https://buildbot2.rust-lang.org/homu/queue/rust
|
[merge-queue]: https://buildbot2.rust-lang.org/homu/queue/rust
|
||||||
|
|
||||||
Speaking of tests, Rust has a comprehensive test suite. More information about
|
Speaking of tests, Rust has a comprehensive test suite. More information about
|
||||||
it can be found
|
it can be found [here][rctd].
|
||||||
[here](https://github.com/rust-lang/rust/blob/master/src/test/COMPILER_TESTS.md).
|
|
||||||
|
|
||||||
### External Dependencies
|
### External Dependencies
|
||||||
[external-dependencies]: #external-dependencies
|
[external-dependencies]: #external-dependencies
|
||||||
@@ -654,5 +653,5 @@ are:
|
|||||||
[rustforge]: https://forge.rust-lang.org/
|
[rustforge]: https://forge.rust-lang.org/
|
||||||
[tlgba]: http://tomlee.co/2014/04/a-more-detailed-tour-of-the-rust-compiler/
|
[tlgba]: http://tomlee.co/2014/04/a-more-detailed-tour-of-the-rust-compiler/
|
||||||
[ro]: http://www.rustaceans.org/
|
[ro]: http://www.rustaceans.org/
|
||||||
[rctd]: ./src/test/COMPILER_TESTS.md
|
[rctd]: https://rust-lang-nursery.github.io/rustc-guide/tests/intro.html
|
||||||
[cheatsheet]: https://buildbot2.rust-lang.org/homu/
|
[cheatsheet]: https://buildbot2.rust-lang.org/homu/
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ Cargo
|
|||||||
using `--target`][cargo/5614]
|
using `--target`][cargo/5614]
|
||||||
- [Added the `cargo-fix` subcommand to automatically move project code from
|
- [Added the `cargo-fix` subcommand to automatically move project code from
|
||||||
2015 edition to 2018.][cargo/5723]
|
2015 edition to 2018.][cargo/5723]
|
||||||
|
- [`cargo doc` can now optionally document private types using the
|
||||||
|
`--document-private-items` flag.][cargo/5543]
|
||||||
|
|
||||||
Misc
|
Misc
|
||||||
----
|
----
|
||||||
@@ -68,6 +70,7 @@ Compatibility Notes
|
|||||||
[51178]: https://github.com/rust-lang/rust/pull/51178/
|
[51178]: https://github.com/rust-lang/rust/pull/51178/
|
||||||
[51122]: https://github.com/rust-lang/rust/pull/51122
|
[51122]: https://github.com/rust-lang/rust/pull/51122
|
||||||
[50494]: https://github.com/rust-lang/rust/pull/50494/
|
[50494]: https://github.com/rust-lang/rust/pull/50494/
|
||||||
|
[cargo/5543]: https://github.com/rust-lang/cargo/pull/5543
|
||||||
[cargo/5614]: https://github.com/rust-lang/cargo/pull/5614/
|
[cargo/5614]: https://github.com/rust-lang/cargo/pull/5614/
|
||||||
[cargo/5723]: https://github.com/rust-lang/cargo/pull/5723/
|
[cargo/5723]: https://github.com/rust-lang/cargo/pull/5723/
|
||||||
[cargo/5831]: https://github.com/rust-lang/cargo/pull/5831/
|
[cargo/5831]: https://github.com/rust-lang/cargo/pull/5831/
|
||||||
@@ -370,6 +373,8 @@ Compatibility Notes
|
|||||||
- [The maximum number for `repr(align(N))` is now 2²⁹.][50378] Previously you
|
- [The maximum number for `repr(align(N))` is now 2²⁹.][50378] Previously you
|
||||||
could enter higher numbers but they were not supported by LLVM. Up to 512MB
|
could enter higher numbers but they were not supported by LLVM. Up to 512MB
|
||||||
alignment should cover all use cases.
|
alignment should cover all use cases.
|
||||||
|
- The `.description()` method on the `std::error::Error` trait
|
||||||
|
[has been soft-deprecated][50163]. It is no longer required to implement it.
|
||||||
|
|
||||||
[48553]: https://github.com/rust-lang/rust/pull/48553/
|
[48553]: https://github.com/rust-lang/rust/pull/48553/
|
||||||
[48851]: https://github.com/rust-lang/rust/pull/48851/
|
[48851]: https://github.com/rust-lang/rust/pull/48851/
|
||||||
@@ -383,6 +388,7 @@ Compatibility Notes
|
|||||||
[49719]: https://github.com/rust-lang/rust/pull/49719/
|
[49719]: https://github.com/rust-lang/rust/pull/49719/
|
||||||
[49896]: https://github.com/rust-lang/rust/pull/49896/
|
[49896]: https://github.com/rust-lang/rust/pull/49896/
|
||||||
[49968]: https://github.com/rust-lang/rust/pull/49968/
|
[49968]: https://github.com/rust-lang/rust/pull/49968/
|
||||||
|
[50163]: https://github.com/rust-lang/rust/pull/50163
|
||||||
[50177]: https://github.com/rust-lang/rust/pull/50177/
|
[50177]: https://github.com/rust-lang/rust/pull/50177/
|
||||||
[50378]: https://github.com/rust-lang/rust/pull/50378/
|
[50378]: https://github.com/rust-lang/rust/pull/50378/
|
||||||
[50398]: https://github.com/rust-lang/rust/pull/50398/
|
[50398]: https://github.com/rust-lang/rust/pull/50398/
|
||||||
|
|||||||
@@ -377,6 +377,10 @@
|
|||||||
# Whether to verify generated LLVM IR
|
# Whether to verify generated LLVM IR
|
||||||
#verify-llvm-ir = false
|
#verify-llvm-ir = false
|
||||||
|
|
||||||
|
# Map all debuginfo paths for libstd and crates to `/rust/$sha/$crate/...`,
|
||||||
|
# generally only set for releases
|
||||||
|
#remap-debuginfo = false
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# Options for specific targets
|
# Options for specific targets
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -263,6 +263,10 @@ fn main() {
|
|||||||
if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() {
|
if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() {
|
||||||
cmd.arg("-Z").arg("force-unstable-if-unmarked");
|
cmd.arg("-Z").arg("force-unstable-if-unmarked");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Ok(map) = env::var("RUSTC_DEBUGINFO_MAP") {
|
||||||
|
cmd.arg("--remap-path-prefix").arg(&map);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Override linker if necessary.
|
// Override linker if necessary.
|
||||||
if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
|
if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ use native;
|
|||||||
use test;
|
use test;
|
||||||
use tool;
|
use tool;
|
||||||
use util::{add_lib_path, exe, libdir};
|
use util::{add_lib_path, exe, libdir};
|
||||||
use {Build, DocTests, Mode};
|
use {Build, DocTests, Mode, GitRepo};
|
||||||
|
|
||||||
pub use Compiler;
|
pub use Compiler;
|
||||||
|
|
||||||
@@ -876,6 +876,10 @@ impl<'a> Builder<'a> {
|
|||||||
cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
|
cargo.env("RUSTC_HOST_CRT_STATIC", x.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(map) = self.build.debuginfo_map(GitRepo::Rustc) {
|
||||||
|
cargo.env("RUSTC_DEBUGINFO_MAP", map);
|
||||||
|
}
|
||||||
|
|
||||||
// Enable usage of unstable features
|
// Enable usage of unstable features
|
||||||
cargo.env("RUSTC_BOOTSTRAP", "1");
|
cargo.env("RUSTC_BOOTSTRAP", "1");
|
||||||
self.add_rust_test_threads(&mut cargo);
|
self.add_rust_test_threads(&mut cargo);
|
||||||
@@ -964,7 +968,7 @@ impl<'a> Builder<'a> {
|
|||||||
let cc = ccacheify(&self.cc(target));
|
let cc = ccacheify(&self.cc(target));
|
||||||
cargo.env(format!("CC_{}", target), &cc).env("CC", &cc);
|
cargo.env(format!("CC_{}", target), &cc).env("CC", &cc);
|
||||||
|
|
||||||
let cflags = self.cflags(target).join(" ");
|
let cflags = self.cflags(target, GitRepo::Rustc).join(" ");
|
||||||
cargo
|
cargo
|
||||||
.env(format!("CFLAGS_{}", target), cflags.clone())
|
.env(format!("CFLAGS_{}", target), cflags.clone())
|
||||||
.env("CFLAGS", cflags.clone());
|
.env("CFLAGS", cflags.clone());
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ use std::process::Command;
|
|||||||
use build_helper::output;
|
use build_helper::output;
|
||||||
use cc;
|
use cc;
|
||||||
|
|
||||||
use Build;
|
use {Build, GitRepo};
|
||||||
use config::Target;
|
use config::Target;
|
||||||
use cache::Interned;
|
use cache::Interned;
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ pub fn find(build: &mut Build) {
|
|||||||
|
|
||||||
build.cc.insert(target, compiler);
|
build.cc.insert(target, compiler);
|
||||||
build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target)));
|
build.verbose(&format!("CC_{} = {:?}", &target, build.cc(target)));
|
||||||
build.verbose(&format!("CFLAGS_{} = {:?}", &target, build.cflags(target)));
|
build.verbose(&format!("CFLAGS_{} = {:?}", &target, build.cflags(target, GitRepo::Rustc)));
|
||||||
if let Some(ar) = ar {
|
if let Some(ar) = ar {
|
||||||
build.verbose(&format!("AR_{} = {:?}", &target, ar));
|
build.verbose(&format!("AR_{} = {:?}", &target, ar));
|
||||||
build.ar.insert(target, ar);
|
build.ar.insert(target, ar);
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use filetime::FileTime;
|
|||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
use util::{exe, libdir, is_dylib, CiEnv};
|
use util::{exe, libdir, is_dylib, CiEnv};
|
||||||
use {Compiler, Mode};
|
use {Compiler, Mode, GitRepo};
|
||||||
use native;
|
use native;
|
||||||
use tool;
|
use tool;
|
||||||
|
|
||||||
@@ -895,7 +895,7 @@ pub fn compiler_file(builder: &Builder,
|
|||||||
target: Interned<String>,
|
target: Interned<String>,
|
||||||
file: &str) -> PathBuf {
|
file: &str) -> PathBuf {
|
||||||
let mut cmd = Command::new(compiler);
|
let mut cmd = Command::new(compiler);
|
||||||
cmd.args(builder.cflags(target));
|
cmd.args(builder.cflags(target, GitRepo::Rustc));
|
||||||
cmd.arg(format!("-print-file-name={}", file));
|
cmd.arg(format!("-print-file-name={}", file));
|
||||||
let out = output(&mut cmd);
|
let out = output(&mut cmd);
|
||||||
PathBuf::from(out.trim())
|
PathBuf::from(out.trim())
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ pub struct Config {
|
|||||||
pub rust_codegen_backends: Vec<Interned<String>>,
|
pub rust_codegen_backends: Vec<Interned<String>>,
|
||||||
pub rust_codegen_backends_dir: String,
|
pub rust_codegen_backends_dir: String,
|
||||||
pub rust_verify_llvm_ir: bool,
|
pub rust_verify_llvm_ir: bool,
|
||||||
|
pub rust_remap_debuginfo: bool,
|
||||||
|
|
||||||
pub build: Interned<String>,
|
pub build: Interned<String>,
|
||||||
pub hosts: Vec<Interned<String>>,
|
pub hosts: Vec<Interned<String>>,
|
||||||
@@ -321,6 +322,7 @@ struct Rust {
|
|||||||
deny_warnings: Option<bool>,
|
deny_warnings: Option<bool>,
|
||||||
backtrace_on_ice: Option<bool>,
|
backtrace_on_ice: Option<bool>,
|
||||||
verify_llvm_ir: Option<bool>,
|
verify_llvm_ir: Option<bool>,
|
||||||
|
remap_debuginfo: Option<bool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TOML representation of how each build target is configured.
|
/// TOML representation of how each build target is configured.
|
||||||
@@ -557,6 +559,7 @@ impl Config {
|
|||||||
set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings));
|
set(&mut config.deny_warnings, rust.deny_warnings.or(flags.warnings));
|
||||||
set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
|
set(&mut config.backtrace_on_ice, rust.backtrace_on_ice);
|
||||||
set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
|
set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir);
|
||||||
|
set(&mut config.rust_remap_debuginfo, rust.remap_debuginfo);
|
||||||
|
|
||||||
if let Some(ref backends) = rust.codegen_backends {
|
if let Some(ref backends) = rust.codegen_backends {
|
||||||
config.rust_codegen_backends = backends.iter()
|
config.rust_codegen_backends = backends.iter()
|
||||||
|
|||||||
@@ -237,6 +237,11 @@ pub enum DocTests {
|
|||||||
Only,
|
Only,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum GitRepo {
|
||||||
|
Rustc,
|
||||||
|
Llvm,
|
||||||
|
}
|
||||||
|
|
||||||
/// Global configuration for the build system.
|
/// Global configuration for the build system.
|
||||||
///
|
///
|
||||||
/// This structure transitively contains all configuration for the build system.
|
/// This structure transitively contains all configuration for the build system.
|
||||||
@@ -738,6 +743,21 @@ impl Build {
|
|||||||
self.config.jobs.unwrap_or_else(|| num_cpus::get() as u32)
|
self.config.jobs.unwrap_or_else(|| num_cpus::get() as u32)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn debuginfo_map(&self, which: GitRepo) -> Option<String> {
|
||||||
|
if !self.config.rust_remap_debuginfo {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = match which {
|
||||||
|
GitRepo::Rustc => {
|
||||||
|
let sha = self.rust_info.sha().expect("failed to find sha");
|
||||||
|
format!("/rustc/{}", sha)
|
||||||
|
}
|
||||||
|
GitRepo::Llvm => format!("/rustc/llvm"),
|
||||||
|
};
|
||||||
|
Some(format!("{}={}", self.src.display(), path))
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the path to the C compiler for the target specified.
|
/// Returns the path to the C compiler for the target specified.
|
||||||
fn cc(&self, target: Interned<String>) -> &Path {
|
fn cc(&self, target: Interned<String>) -> &Path {
|
||||||
self.cc[&target].path()
|
self.cc[&target].path()
|
||||||
@@ -745,7 +765,7 @@ impl Build {
|
|||||||
|
|
||||||
/// Returns a list of flags to pass to the C compiler for the target
|
/// Returns a list of flags to pass to the C compiler for the target
|
||||||
/// specified.
|
/// specified.
|
||||||
fn cflags(&self, target: Interned<String>) -> Vec<String> {
|
fn cflags(&self, target: Interned<String>, which: GitRepo) -> Vec<String> {
|
||||||
// Filter out -O and /O (the optimization flags) that we picked up from
|
// Filter out -O and /O (the optimization flags) that we picked up from
|
||||||
// cc-rs because the build scripts will determine that for themselves.
|
// cc-rs because the build scripts will determine that for themselves.
|
||||||
let mut base = self.cc[&target].args().iter()
|
let mut base = self.cc[&target].args().iter()
|
||||||
@@ -767,6 +787,16 @@ impl Build {
|
|||||||
if &*target == "i686-pc-windows-gnu" {
|
if &*target == "i686-pc-windows-gnu" {
|
||||||
base.push("-fno-omit-frame-pointer".into());
|
base.push("-fno-omit-frame-pointer".into());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(map) = self.debuginfo_map(which) {
|
||||||
|
let cc = self.cc(target);
|
||||||
|
if cc.ends_with("clang") || cc.ends_with("gcc") {
|
||||||
|
base.push(format!("-fdebug-prefix-map={}", map).into());
|
||||||
|
} else if cc.ends_with("clang-cl.exe") {
|
||||||
|
base.push("-Xclang".into());
|
||||||
|
base.push(format!("-fdebug-prefix-map={}", map).into());
|
||||||
|
}
|
||||||
|
}
|
||||||
base
|
base
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use util::{self, exe};
|
|||||||
use build_helper::up_to_date;
|
use build_helper::up_to_date;
|
||||||
use builder::{Builder, RunConfig, ShouldRun, Step};
|
use builder::{Builder, RunConfig, ShouldRun, Step};
|
||||||
use cache::Interned;
|
use cache::Interned;
|
||||||
|
use GitRepo;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
pub struct Llvm {
|
pub struct Llvm {
|
||||||
@@ -373,8 +374,8 @@ fn configure_cmake(builder: &Builder,
|
|||||||
}
|
}
|
||||||
|
|
||||||
cfg.build_arg("-j").build_arg(builder.jobs().to_string());
|
cfg.build_arg("-j").build_arg(builder.jobs().to_string());
|
||||||
cfg.define("CMAKE_C_FLAGS", builder.cflags(target).join(" "));
|
cfg.define("CMAKE_C_FLAGS", builder.cflags(target, GitRepo::Llvm).join(" "));
|
||||||
let mut cxxflags = builder.cflags(target).join(" ");
|
let mut cxxflags = builder.cflags(target, GitRepo::Llvm).join(" ");
|
||||||
if building_dist_binaries {
|
if building_dist_binaries {
|
||||||
if builder.config.llvm_static_stdcpp && !target.contains("windows") {
|
if builder.config.llvm_static_stdcpp && !target.contains("windows") {
|
||||||
cxxflags.push_str(" -static-libstdc++");
|
cxxflags.push_str(" -static-libstdc++");
|
||||||
@@ -680,7 +681,7 @@ impl Step for Openssl {
|
|||||||
};
|
};
|
||||||
configure.arg(os);
|
configure.arg(os);
|
||||||
configure.env("CC", builder.cc(target));
|
configure.env("CC", builder.cc(target));
|
||||||
for flag in builder.cflags(target) {
|
for flag in builder.cflags(target, GitRepo::Rustc) {
|
||||||
configure.arg(flag);
|
configure.arg(flag);
|
||||||
}
|
}
|
||||||
// There is no specific os target for android aarch64 or x86_64,
|
// There is no specific os target for android aarch64 or x86_64,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ use tool::{self, Tool, SourceType};
|
|||||||
use toolstate::ToolState;
|
use toolstate::ToolState;
|
||||||
use util::{self, dylib_path, dylib_path_var};
|
use util::{self, dylib_path, dylib_path_var};
|
||||||
use Crate as CargoCrate;
|
use Crate as CargoCrate;
|
||||||
use {DocTests, Mode};
|
use {DocTests, Mode, GitRepo};
|
||||||
|
|
||||||
const ADB_TEST_DIR: &str = "/data/tmp/work";
|
const ADB_TEST_DIR: &str = "/data/tmp/work";
|
||||||
|
|
||||||
@@ -1142,7 +1142,7 @@ impl Step for Compiletest {
|
|||||||
.arg("--cxx")
|
.arg("--cxx")
|
||||||
.arg(builder.cxx(target).unwrap())
|
.arg(builder.cxx(target).unwrap())
|
||||||
.arg("--cflags")
|
.arg("--cflags")
|
||||||
.arg(builder.cflags(target).join(" "))
|
.arg(builder.cflags(target, GitRepo::Rustc).join(" "))
|
||||||
.arg("--llvm-components")
|
.arg("--llvm-components")
|
||||||
.arg(llvm_components.trim())
|
.arg(llvm_components.trim())
|
||||||
.arg("--llvm-cxxflags")
|
.arg("--llvm-cxxflags")
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ export RUST_RELEASE_CHANNEL=nightly
|
|||||||
if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
|
if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
|
||||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
|
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
|
||||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
|
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
|
||||||
|
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo"
|
||||||
|
|
||||||
if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
|
if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
|
||||||
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
|
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
|
||||||
|
|||||||
@@ -68,15 +68,13 @@ pub enum OptLevel {
|
|||||||
SizeMin, // -Oz
|
SizeMin, // -Oz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This is what the `LtoCli` values get mapped to after resolving defaults and
|
||||||
|
/// and taking other command line options into account.
|
||||||
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||||
pub enum Lto {
|
pub enum Lto {
|
||||||
/// Don't do any LTO whatsoever
|
/// Don't do any LTO whatsoever
|
||||||
No,
|
No,
|
||||||
|
|
||||||
/// Do a full crate graph LTO. The flavor is determined by the compiler
|
|
||||||
/// (currently the default is "fat").
|
|
||||||
Yes,
|
|
||||||
|
|
||||||
/// Do a full crate graph LTO with ThinLTO
|
/// Do a full crate graph LTO with ThinLTO
|
||||||
Thin,
|
Thin,
|
||||||
|
|
||||||
@@ -88,6 +86,23 @@ pub enum Lto {
|
|||||||
Fat,
|
Fat,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The different settings that the `-C lto` flag can have.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Hash, Debug)]
|
||||||
|
pub enum LtoCli {
|
||||||
|
/// `-C lto=no`
|
||||||
|
No,
|
||||||
|
/// `-C lto=yes`
|
||||||
|
Yes,
|
||||||
|
/// `-C lto`
|
||||||
|
NoParam,
|
||||||
|
/// `-C lto=thin`
|
||||||
|
Thin,
|
||||||
|
/// `-C lto=fat`
|
||||||
|
Fat,
|
||||||
|
/// No `-C lto` flag passed
|
||||||
|
Unspecified,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Hash)]
|
#[derive(Clone, PartialEq, Hash)]
|
||||||
pub enum CrossLangLto {
|
pub enum CrossLangLto {
|
||||||
LinkerPlugin(PathBuf),
|
LinkerPlugin(PathBuf),
|
||||||
@@ -801,7 +816,8 @@ macro_rules! options {
|
|||||||
pub const parse_unpretty: Option<&'static str> =
|
pub const parse_unpretty: Option<&'static str> =
|
||||||
Some("`string` or `string=string`");
|
Some("`string` or `string=string`");
|
||||||
pub const parse_lto: Option<&'static str> =
|
pub const parse_lto: Option<&'static str> =
|
||||||
Some("one of `thin`, `fat`, or omitted");
|
Some("either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, \
|
||||||
|
`fat`, or omitted");
|
||||||
pub const parse_cross_lang_lto: Option<&'static str> =
|
pub const parse_cross_lang_lto: Option<&'static str> =
|
||||||
Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
|
Some("either a boolean (`yes`, `no`, `on`, `off`, etc), \
|
||||||
or the path to the linker plugin");
|
or the path to the linker plugin");
|
||||||
@@ -809,7 +825,7 @@ macro_rules! options {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod $mod_set {
|
mod $mod_set {
|
||||||
use super::{$struct_name, Passes, Sanitizer, Lto, CrossLangLto};
|
use super::{$struct_name, Passes, Sanitizer, LtoCli, CrossLangLto};
|
||||||
use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
|
use rustc_target::spec::{LinkerFlavor, PanicStrategy, RelroLevel};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@@ -1002,11 +1018,23 @@ macro_rules! options {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
|
fn parse_lto(slot: &mut LtoCli, v: Option<&str>) -> bool {
|
||||||
|
if v.is_some() {
|
||||||
|
let mut bool_arg = None;
|
||||||
|
if parse_opt_bool(&mut bool_arg, v) {
|
||||||
|
*slot = if bool_arg.unwrap() {
|
||||||
|
LtoCli::Yes
|
||||||
|
} else {
|
||||||
|
LtoCli::No
|
||||||
|
};
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
*slot = match v {
|
*slot = match v {
|
||||||
None => Lto::Yes,
|
None => LtoCli::NoParam,
|
||||||
Some("thin") => Lto::Thin,
|
Some("thin") => LtoCli::Thin,
|
||||||
Some("fat") => Lto::Fat,
|
Some("fat") => LtoCli::Fat,
|
||||||
Some(_) => return false,
|
Some(_) => return false,
|
||||||
};
|
};
|
||||||
true
|
true
|
||||||
@@ -1047,7 +1075,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
|||||||
"extra arguments to append to the linker invocation (space separated)"),
|
"extra arguments to append to the linker invocation (space separated)"),
|
||||||
link_dead_code: bool = (false, parse_bool, [UNTRACKED],
|
link_dead_code: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"don't let linker strip dead code (turning it on can be used for code coverage)"),
|
"don't let linker strip dead code (turning it on can be used for code coverage)"),
|
||||||
lto: Lto = (Lto::No, parse_lto, [TRACKED],
|
lto: LtoCli = (LtoCli::Unspecified, parse_lto, [TRACKED],
|
||||||
"perform LLVM link-time optimizations"),
|
"perform LLVM link-time optimizations"),
|
||||||
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
|
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||||
"select target processor (rustc --print target-cpus for details)"),
|
"select target processor (rustc --print target-cpus for details)"),
|
||||||
@@ -2384,8 +2412,8 @@ mod dep_tracking {
|
|||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use super::{CrateType, DebugInfo, ErrorOutputType, Lto, OptLevel, OutputTypes,
|
use super::{CrateType, DebugInfo, ErrorOutputType, OptLevel, OutputTypes,
|
||||||
Passes, Sanitizer, CrossLangLto};
|
Passes, Sanitizer, LtoCli, CrossLangLto};
|
||||||
use syntax::feature_gate::UnstableFeatures;
|
use syntax::feature_gate::UnstableFeatures;
|
||||||
use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
|
use rustc_target::spec::{PanicStrategy, RelroLevel, TargetTriple};
|
||||||
use syntax::edition::Edition;
|
use syntax::edition::Edition;
|
||||||
@@ -2440,7 +2468,7 @@ mod dep_tracking {
|
|||||||
impl_dep_tracking_hash_via_hash!(RelroLevel);
|
impl_dep_tracking_hash_via_hash!(RelroLevel);
|
||||||
impl_dep_tracking_hash_via_hash!(Passes);
|
impl_dep_tracking_hash_via_hash!(Passes);
|
||||||
impl_dep_tracking_hash_via_hash!(OptLevel);
|
impl_dep_tracking_hash_via_hash!(OptLevel);
|
||||||
impl_dep_tracking_hash_via_hash!(Lto);
|
impl_dep_tracking_hash_via_hash!(LtoCli);
|
||||||
impl_dep_tracking_hash_via_hash!(DebugInfo);
|
impl_dep_tracking_hash_via_hash!(DebugInfo);
|
||||||
impl_dep_tracking_hash_via_hash!(UnstableFeatures);
|
impl_dep_tracking_hash_via_hash!(UnstableFeatures);
|
||||||
impl_dep_tracking_hash_via_hash!(OutputTypes);
|
impl_dep_tracking_hash_via_hash!(OutputTypes);
|
||||||
@@ -2514,7 +2542,7 @@ mod tests {
|
|||||||
use lint;
|
use lint;
|
||||||
use middle::cstore;
|
use middle::cstore;
|
||||||
use session::config::{build_configuration, build_session_options_and_crate_config};
|
use session::config::{build_configuration, build_session_options_and_crate_config};
|
||||||
use session::config::{Lto, CrossLangLto};
|
use session::config::{LtoCli, CrossLangLto};
|
||||||
use session::build_session;
|
use session::build_session;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
@@ -2948,7 +2976,7 @@ mod tests {
|
|||||||
|
|
||||||
// Make sure changing a [TRACKED] option changes the hash
|
// Make sure changing a [TRACKED] option changes the hash
|
||||||
opts = reference.clone();
|
opts = reference.clone();
|
||||||
opts.cg.lto = Lto::Fat;
|
opts.cg.lto = LtoCli::Fat;
|
||||||
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
|
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
|
||||||
|
|
||||||
opts = reference.clone();
|
opts = reference.clone();
|
||||||
|
|||||||
@@ -550,9 +550,27 @@ impl Session {
|
|||||||
// lto` and we've for whatever reason forced off ThinLTO via the CLI,
|
// lto` and we've for whatever reason forced off ThinLTO via the CLI,
|
||||||
// then ensure we can't use a ThinLTO.
|
// then ensure we can't use a ThinLTO.
|
||||||
match self.opts.cg.lto {
|
match self.opts.cg.lto {
|
||||||
config::Lto::No => {}
|
config::LtoCli::Unspecified => {
|
||||||
config::Lto::Yes if self.opts.cli_forced_thinlto_off => return config::Lto::Fat,
|
// The compiler was invoked without the `-Clto` flag. Fall
|
||||||
other => return other,
|
// through to the default handling
|
||||||
|
}
|
||||||
|
config::LtoCli::No => {
|
||||||
|
// The user explicitly opted out of any kind of LTO
|
||||||
|
return config::Lto::No;
|
||||||
|
}
|
||||||
|
config::LtoCli::Yes |
|
||||||
|
config::LtoCli::Fat |
|
||||||
|
config::LtoCli::NoParam => {
|
||||||
|
// All of these mean fat LTO
|
||||||
|
return config::Lto::Fat;
|
||||||
|
}
|
||||||
|
config::LtoCli::Thin => {
|
||||||
|
return if self.opts.cli_forced_thinlto_off {
|
||||||
|
config::Lto::Fat
|
||||||
|
} else {
|
||||||
|
config::Lto::Thin
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ok at this point the target doesn't require anything and the user
|
// Ok at this point the target doesn't require anything and the user
|
||||||
@@ -1178,7 +1196,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
|
|||||||
|
|
||||||
if sess.opts.incremental.is_some() {
|
if sess.opts.incremental.is_some() {
|
||||||
match sess.lto() {
|
match sess.lto() {
|
||||||
Lto::Yes |
|
|
||||||
Lto::Thin |
|
Lto::Thin |
|
||||||
Lto::Fat => {
|
Lto::Fat => {
|
||||||
sess.err("can't perform LTO when compiling incrementally");
|
sess.err("can't perform LTO when compiling incrementally");
|
||||||
|
|||||||
@@ -1666,7 +1666,6 @@ fn relevant_lib(sess: &Session, lib: &NativeLibrary) -> bool {
|
|||||||
|
|
||||||
fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
|
fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
|
||||||
match sess.lto() {
|
match sess.lto() {
|
||||||
Lto::Yes |
|
|
||||||
Lto::Fat => true,
|
Lto::Fat => true,
|
||||||
Lto::Thin => {
|
Lto::Thin => {
|
||||||
// If we defer LTO to the linker, we haven't run LTO ourselves, so
|
// If we defer LTO to the linker, we haven't run LTO ourselves, so
|
||||||
|
|||||||
@@ -205,13 +205,12 @@ impl<'a> GccLinker<'a> {
|
|||||||
self.linker_arg(&format!("-plugin-opt={}", opt_level));
|
self.linker_arg(&format!("-plugin-opt={}", opt_level));
|
||||||
self.linker_arg(&format!("-plugin-opt=mcpu={}", llvm_util::target_cpu(self.sess)));
|
self.linker_arg(&format!("-plugin-opt=mcpu={}", llvm_util::target_cpu(self.sess)));
|
||||||
|
|
||||||
match self.sess.opts.cg.lto {
|
match self.sess.lto() {
|
||||||
config::Lto::Thin |
|
config::Lto::Thin |
|
||||||
config::Lto::ThinLocal => {
|
config::Lto::ThinLocal => {
|
||||||
self.linker_arg("-plugin-opt=thin");
|
self.linker_arg("-plugin-opt=thin");
|
||||||
}
|
}
|
||||||
config::Lto::Fat |
|
config::Lto::Fat |
|
||||||
config::Lto::Yes |
|
|
||||||
config::Lto::No => {
|
config::Lto::No => {
|
||||||
// default to regular LTO
|
// default to regular LTO
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ pub(crate) fn run(cgcx: &CodegenContext,
|
|||||||
Lto::ThinLocal => SymbolExportLevel::Rust,
|
Lto::ThinLocal => SymbolExportLevel::Rust,
|
||||||
|
|
||||||
// We're doing LTO for the entire crate graph
|
// We're doing LTO for the entire crate graph
|
||||||
Lto::Yes | Lto::Fat | Lto::Thin => {
|
Lto::Fat | Lto::Thin => {
|
||||||
symbol_export::crates_export_threshold(&cgcx.crate_types)
|
symbol_export::crates_export_threshold(&cgcx.crate_types)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,6 @@ pub(crate) fn run(cgcx: &CodegenContext,
|
|||||||
.map(|c| c.as_ptr())
|
.map(|c| c.as_ptr())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
match cgcx.lto {
|
match cgcx.lto {
|
||||||
Lto::Yes | // `-C lto` == fat LTO by default
|
|
||||||
Lto::Fat => {
|
Lto::Fat => {
|
||||||
assert!(cached_modules.is_empty());
|
assert!(cached_modules.is_empty());
|
||||||
let opt_jobs = fat_lto(cgcx,
|
let opt_jobs = fat_lto(cgcx,
|
||||||
|
|||||||
@@ -937,7 +937,6 @@ fn need_pre_thin_lto_bitcode_for_incr_comp(sess: &Session) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match sess.lto() {
|
match sess.lto() {
|
||||||
Lto::Yes |
|
|
||||||
Lto::Fat |
|
Lto::Fat |
|
||||||
Lto::No => false,
|
Lto::No => false,
|
||||||
Lto::Thin |
|
Lto::Thin |
|
||||||
@@ -1372,7 +1371,7 @@ fn execute_optimize_work_item(cgcx: &CodegenContext,
|
|||||||
// require LTO so the request for LTO is always unconditionally
|
// require LTO so the request for LTO is always unconditionally
|
||||||
// passed down to the backend, but we don't actually want to do
|
// passed down to the backend, but we don't actually want to do
|
||||||
// anything about it yet until we've got a final product.
|
// anything about it yet until we've got a final product.
|
||||||
Lto::Yes | Lto::Fat | Lto::Thin => {
|
Lto::Fat | Lto::Thin => {
|
||||||
cgcx.crate_types.len() != 1 ||
|
cgcx.crate_types.len() != 1 ||
|
||||||
cgcx.crate_types[0] != config::CrateType::Rlib
|
cgcx.crate_types[0] != config::CrateType::Rlib
|
||||||
}
|
}
|
||||||
@@ -1552,7 +1551,7 @@ fn start_executing_work(tcx: TyCtxt,
|
|||||||
exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
|
exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
|
||||||
Some(Arc::new(exported_symbols))
|
Some(Arc::new(exported_symbols))
|
||||||
}
|
}
|
||||||
Lto::Yes | Lto::Fat | Lto::Thin => {
|
Lto::Fat | Lto::Thin => {
|
||||||
exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
|
exported_symbols.insert(LOCAL_CRATE, copy_symbols(LOCAL_CRATE));
|
||||||
for &cnum in tcx.crates().iter() {
|
for &cnum in tcx.crates().iter() {
|
||||||
exported_symbols.insert(cnum, copy_symbols(cnum));
|
exported_symbols.insert(cnum, copy_symbols(cnum));
|
||||||
|
|||||||
@@ -239,6 +239,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
|
|||||||
type MemoryKinds = !;
|
type MemoryKinds = !;
|
||||||
|
|
||||||
const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
|
const MUT_STATIC_KIND: Option<!> = None; // no mutating of statics allowed
|
||||||
|
const DETECT_LOOPS: bool = true;
|
||||||
|
|
||||||
fn find_fn<'a>(
|
fn find_fn<'a>(
|
||||||
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ pub struct EvalContext<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
|
|||||||
/// detector period.
|
/// detector period.
|
||||||
pub(super) steps_since_detector_enabled: isize,
|
pub(super) steps_since_detector_enabled: isize,
|
||||||
|
|
||||||
|
/// Extra state to detect loops.
|
||||||
|
/// FIXME: Move this to the CTFE machine's state, out of the general miri engine.
|
||||||
pub(super) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>,
|
pub(super) loop_detector: InfiniteLoopDetector<'a, 'mir, 'tcx, M>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +112,7 @@ pub struct Frame<'mir, 'tcx: 'mir> {
|
|||||||
pub stmt: usize,
|
pub stmt: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not using the macro because that does not support types depending on 'tcx
|
||||||
impl<'a, 'mir, 'tcx: 'mir> HashStable<StableHashingContext<'a>> for Frame<'mir, 'tcx> {
|
impl<'a, 'mir, 'tcx: 'mir> HashStable<StableHashingContext<'a>> for Frame<'mir, 'tcx> {
|
||||||
fn hash_stable<W: StableHasherResult>(
|
fn hash_stable<W: StableHasherResult>(
|
||||||
&self,
|
&self,
|
||||||
@@ -144,11 +147,14 @@ pub enum StackPopCleanup {
|
|||||||
None { cleanup: bool },
|
None { cleanup: bool },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can't use the macro here because that does not support named enum fields.
|
||||||
impl<'a> HashStable<StableHashingContext<'a>> for StackPopCleanup {
|
impl<'a> HashStable<StableHashingContext<'a>> for StackPopCleanup {
|
||||||
fn hash_stable<W: StableHasherResult>(
|
fn hash_stable<W: StableHasherResult>(
|
||||||
&self,
|
&self,
|
||||||
hcx: &mut StableHashingContext<'a>,
|
hcx: &mut StableHashingContext<'a>,
|
||||||
hasher: &mut StableHasher<W>) {
|
hasher: &mut StableHasher<W>)
|
||||||
|
{
|
||||||
|
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||||
match self {
|
match self {
|
||||||
StackPopCleanup::Goto(ref block) => block.hash_stable(hcx, hasher),
|
StackPopCleanup::Goto(ref block) => block.hash_stable(hcx, hasher),
|
||||||
StackPopCleanup::None { cleanup } => cleanup.hash_stable(hcx, hasher),
|
StackPopCleanup::None { cleanup } => cleanup.hash_stable(hcx, hasher),
|
||||||
|
|||||||
@@ -12,29 +12,29 @@
|
|||||||
//! This separation exists to ensure that no fancy miri features like
|
//! This separation exists to ensure that no fancy miri features like
|
||||||
//! interpreting common C functions leak into CTFE.
|
//! interpreting common C functions leak into CTFE.
|
||||||
|
|
||||||
use std::hash::Hash;
|
|
||||||
|
|
||||||
use rustc::hir::def_id::DefId;
|
use rustc::hir::def_id::DefId;
|
||||||
use rustc::ich::StableHashingContext;
|
|
||||||
use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
|
use rustc::mir::interpret::{Allocation, EvalResult, Scalar};
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
|
use rustc::ty::{self, layout::TyLayout, query::TyCtxtAt};
|
||||||
use rustc_data_structures::stable_hasher::HashStable;
|
|
||||||
|
|
||||||
use super::{EvalContext, PlaceTy, OpTy};
|
use super::{EvalContext, PlaceTy, OpTy};
|
||||||
|
|
||||||
/// Methods of this trait signifies a point where CTFE evaluation would fail
|
/// Methods of this trait signifies a point where CTFE evaluation would fail
|
||||||
/// and some use case dependent behaviour can instead be applied
|
/// and some use case dependent behaviour can instead be applied
|
||||||
pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>> {
|
pub trait Machine<'mir, 'tcx>: Clone + Eq {
|
||||||
/// Additional data that can be accessed via the Memory
|
/// Additional data that can be accessed via the Memory
|
||||||
type MemoryData: Clone + Eq + Hash + for<'a> HashStable<StableHashingContext<'a>>;
|
type MemoryData: Clone + Eq;
|
||||||
|
|
||||||
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
|
/// Additional memory kinds a machine wishes to distinguish from the builtin ones
|
||||||
type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq + Hash;
|
type MemoryKinds: ::std::fmt::Debug + Copy + Clone + Eq;
|
||||||
|
|
||||||
/// The memory kind to use for mutated statics -- or None if those are not supported.
|
/// The memory kind to use for mutated statics -- or None if those are not supported.
|
||||||
const MUT_STATIC_KIND: Option<Self::MemoryKinds>;
|
const MUT_STATIC_KIND: Option<Self::MemoryKinds>;
|
||||||
|
|
||||||
|
/// Whether to attempt to detect infinite loops (any kind of infinite
|
||||||
|
/// execution, really).
|
||||||
|
const DETECT_LOOPS: bool;
|
||||||
|
|
||||||
/// Entry point to all function calls.
|
/// Entry point to all function calls.
|
||||||
///
|
///
|
||||||
/// Returns either the mir to use for the call, or `None` if execution should
|
/// Returns either the mir to use for the call, or `None` if execution should
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
//! All high-level functions to write to memory work on places as destinations.
|
//! All high-level functions to write to memory work on places as destinations.
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use rustc::ich::StableHashingContext;
|
use rustc::ich::StableHashingContext;
|
||||||
use rustc::mir;
|
use rustc::mir;
|
||||||
@@ -57,11 +58,13 @@ pub enum Place<Id=AllocId> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Can't use the macro here because that does not support named enum fields.
|
||||||
impl<'a> HashStable<StableHashingContext<'a>> for Place {
|
impl<'a> HashStable<StableHashingContext<'a>> for Place {
|
||||||
fn hash_stable<W: StableHasherResult>(
|
fn hash_stable<W: StableHasherResult>(
|
||||||
&self, hcx: &mut StableHashingContext<'a>,
|
&self, hcx: &mut StableHashingContext<'a>,
|
||||||
hasher: &mut StableHasher<W>) {
|
hasher: &mut StableHasher<W>)
|
||||||
|
{
|
||||||
|
mem::discriminant(self).hash_stable(hcx, hasher);
|
||||||
match self {
|
match self {
|
||||||
Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher),
|
Place::Ptr(mem_place) => mem_place.hash_stable(hcx, hasher),
|
||||||
|
|
||||||
|
|||||||
@@ -62,14 +62,13 @@ impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
|
|||||||
pub fn observe_and_analyze(
|
pub fn observe_and_analyze(
|
||||||
&mut self,
|
&mut self,
|
||||||
tcx: &TyCtxt<'b, 'tcx, 'tcx>,
|
tcx: &TyCtxt<'b, 'tcx, 'tcx>,
|
||||||
machine: &M,
|
|
||||||
memory: &Memory<'a, 'mir, 'tcx, M>,
|
memory: &Memory<'a, 'mir, 'tcx, M>,
|
||||||
stack: &[Frame<'mir, 'tcx>],
|
stack: &[Frame<'mir, 'tcx>],
|
||||||
) -> EvalResult<'tcx, ()> {
|
) -> EvalResult<'tcx, ()> {
|
||||||
|
|
||||||
let mut hcx = tcx.get_stable_hashing_context();
|
let mut hcx = tcx.get_stable_hashing_context();
|
||||||
let mut hasher = StableHasher::<u64>::new();
|
let mut hasher = StableHasher::<u64>::new();
|
||||||
(machine, stack).hash_stable(&mut hcx, &mut hasher);
|
stack.hash_stable(&mut hcx, &mut hasher);
|
||||||
let hash = hasher.finish();
|
let hash = hasher.finish();
|
||||||
|
|
||||||
if self.hashes.insert(hash) {
|
if self.hashes.insert(hash) {
|
||||||
@@ -79,7 +78,7 @@ impl<'a, 'mir, 'tcx, M> InfiniteLoopDetector<'a, 'mir, 'tcx, M>
|
|||||||
|
|
||||||
info!("snapshotting the state of the interpreter");
|
info!("snapshotting the state of the interpreter");
|
||||||
|
|
||||||
if self.snapshots.insert(EvalSnapshot::new(machine, memory, stack)) {
|
if self.snapshots.insert(EvalSnapshot::new(memory, stack)) {
|
||||||
// Spurious collision or first cycle
|
// Spurious collision or first cycle
|
||||||
return Ok(())
|
return Ok(())
|
||||||
}
|
}
|
||||||
@@ -345,7 +344,6 @@ impl<'a, 'b, 'mir, 'tcx, M> SnapshotContext<'b> for Memory<'a, 'mir, 'tcx, M>
|
|||||||
|
|
||||||
/// The virtual machine state during const-evaluation at a given point in time.
|
/// The virtual machine state during const-evaluation at a given point in time.
|
||||||
struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
|
struct EvalSnapshot<'a, 'mir, 'tcx: 'a + 'mir, M: Machine<'mir, 'tcx>> {
|
||||||
machine: M,
|
|
||||||
memory: Memory<'a, 'mir, 'tcx, M>,
|
memory: Memory<'a, 'mir, 'tcx, M>,
|
||||||
stack: Vec<Frame<'mir, 'tcx>>,
|
stack: Vec<Frame<'mir, 'tcx>>,
|
||||||
}
|
}
|
||||||
@@ -354,21 +352,20 @@ impl<'a, 'mir, 'tcx, M> EvalSnapshot<'a, 'mir, 'tcx, M>
|
|||||||
where M: Machine<'mir, 'tcx>,
|
where M: Machine<'mir, 'tcx>,
|
||||||
{
|
{
|
||||||
fn new(
|
fn new(
|
||||||
machine: &M,
|
|
||||||
memory: &Memory<'a, 'mir, 'tcx, M>,
|
memory: &Memory<'a, 'mir, 'tcx, M>,
|
||||||
stack: &[Frame<'mir, 'tcx>]) -> Self {
|
stack: &[Frame<'mir, 'tcx>]
|
||||||
|
) -> Self {
|
||||||
EvalSnapshot {
|
EvalSnapshot {
|
||||||
machine: machine.clone(),
|
|
||||||
memory: memory.clone(),
|
memory: memory.clone(),
|
||||||
stack: stack.into(),
|
stack: stack.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn snapshot<'b: 'a>(&'b self)
|
fn snapshot<'b: 'a>(&'b self)
|
||||||
-> (&'b M, MemorySnapshot<'b, 'mir, 'tcx, M>, Vec<FrameSnapshot<'a, 'tcx>>) {
|
-> (MemorySnapshot<'b, 'mir, 'tcx, M>, Vec<FrameSnapshot<'a, 'tcx>>)
|
||||||
let EvalSnapshot{ machine, memory, stack } = self;
|
{
|
||||||
(&machine, memory.snapshot(), stack.iter().map(|frame| frame.snapshot(memory)).collect())
|
let EvalSnapshot{ memory, stack } = self;
|
||||||
|
(memory.snapshot(), stack.iter().map(|frame| frame.snapshot(memory)).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,6 +381,8 @@ impl<'a, 'mir, 'tcx, M> Hash for EvalSnapshot<'a, 'mir, 'tcx, M>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Not using the macro because we need special handling for `memory`, which the macro
|
||||||
|
// does not support at the same time as the extra bounds on the type.
|
||||||
impl<'a, 'b, 'mir, 'tcx, M> HashStable<StableHashingContext<'b>>
|
impl<'a, 'b, 'mir, 'tcx, M> HashStable<StableHashingContext<'b>>
|
||||||
for EvalSnapshot<'a, 'mir, 'tcx, M>
|
for EvalSnapshot<'a, 'mir, 'tcx, M>
|
||||||
where M: Machine<'mir, 'tcx>,
|
where M: Machine<'mir, 'tcx>,
|
||||||
@@ -391,10 +390,10 @@ impl<'a, 'b, 'mir, 'tcx, M> HashStable<StableHashingContext<'b>>
|
|||||||
fn hash_stable<W: StableHasherResult>(
|
fn hash_stable<W: StableHasherResult>(
|
||||||
&self,
|
&self,
|
||||||
hcx: &mut StableHashingContext<'b>,
|
hcx: &mut StableHashingContext<'b>,
|
||||||
hasher: &mut StableHasher<W>) {
|
hasher: &mut StableHasher<W>)
|
||||||
|
{
|
||||||
let EvalSnapshot{ machine, memory, stack } = self;
|
let EvalSnapshot{ memory: _, stack } = self;
|
||||||
(machine, &memory.data, stack).hash_stable(hcx, hasher);
|
stack.hash_stable(hcx, hasher);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -65,6 +65,10 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !M::DETECT_LOOPS {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
if self.loop_detector.is_empty() {
|
if self.loop_detector.is_empty() {
|
||||||
// First run of the loop detector
|
// First run of the loop detector
|
||||||
|
|
||||||
@@ -75,7 +79,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
|||||||
|
|
||||||
self.loop_detector.observe_and_analyze(
|
self.loop_detector.observe_and_analyze(
|
||||||
&self.tcx,
|
&self.tcx,
|
||||||
&self.machine,
|
|
||||||
&self.memory,
|
&self.memory,
|
||||||
&self.stack[..],
|
&self.stack[..],
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -298,11 +298,21 @@ impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
|
|||||||
TypeVariableOrigin::TypeInference(pat.span)));
|
TypeVariableOrigin::TypeInference(pat.span)));
|
||||||
let element_tys = tcx.mk_type_list(element_tys_iter);
|
let element_tys = tcx.mk_type_list(element_tys_iter);
|
||||||
let pat_ty = tcx.mk_ty(ty::Tuple(element_tys));
|
let pat_ty = tcx.mk_ty(ty::Tuple(element_tys));
|
||||||
self.demand_eqtype(pat.span, expected, pat_ty);
|
if let Some(mut err) = self.demand_eqtype_diag(pat.span, expected, pat_ty) {
|
||||||
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
err.emit();
|
||||||
self.check_pat_walk(elem, &element_tys[i], def_bm, true);
|
// Walk subpatterns with an expected type of `err` in this case to silence
|
||||||
|
// further errors being emitted when using the bindings. #50333
|
||||||
|
let element_tys_iter = (0..max_len).map(|_| tcx.types.err);
|
||||||
|
for (_, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
||||||
|
self.check_pat_walk(elem, &tcx.types.err, def_bm, true);
|
||||||
|
}
|
||||||
|
tcx.mk_tup(element_tys_iter)
|
||||||
|
} else {
|
||||||
|
for (i, elem) in elements.iter().enumerate_and_adjust(max_len, ddpos) {
|
||||||
|
self.check_pat_walk(elem, &element_tys[i], def_bm, true);
|
||||||
|
}
|
||||||
|
pat_ty
|
||||||
}
|
}
|
||||||
pat_ty
|
|
||||||
}
|
}
|
||||||
PatKind::Box(ref inner) => {
|
PatKind::Box(ref inner) => {
|
||||||
let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span));
|
let inner_ty = self.next_ty_var(TypeVariableOrigin::TypeInference(inner.span));
|
||||||
|
|||||||
@@ -97,6 +97,10 @@ fn build_libbacktrace(target: &str) -> Result<(), ()> {
|
|||||||
.file("../libbacktrace/sort.c")
|
.file("../libbacktrace/sort.c")
|
||||||
.file("../libbacktrace/state.c");
|
.file("../libbacktrace/state.c");
|
||||||
|
|
||||||
|
let any_debug = env::var("RUSTC_DEBUGINFO").unwrap_or(String::new()) == "true" ||
|
||||||
|
env::var("RUSTC_DEBUGINFO_LINES").unwrap_or(String::new()) == "true";
|
||||||
|
build.debug(any_debug);
|
||||||
|
|
||||||
if target.contains("darwin") {
|
if target.contains("darwin") {
|
||||||
build.file("../libbacktrace/macho.c");
|
build.file("../libbacktrace/macho.c");
|
||||||
} else if target.contains("windows") {
|
} else if target.contains("windows") {
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ use sys;
|
|||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// // We are certain that our string doesn't have 0 bytes in the middle,
|
/// // We are certain that our string doesn't have 0 bytes in the middle,
|
||||||
/// // so we can .unwrap()
|
/// // so we can .expect()
|
||||||
/// let c_to_print = CString::new("Hello, world!").unwrap();
|
/// let c_to_print = CString::new("Hello, world!").expect("CString::new failed");
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// my_printer(c_to_print.as_ptr());
|
/// my_printer(c_to_print.as_ptr());
|
||||||
/// }
|
/// }
|
||||||
@@ -175,7 +175,7 @@ pub struct CString {
|
|||||||
/// unsafe { work_with(data.as_ptr()) }
|
/// unsafe { work_with(data.as_ptr()) }
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let s = CString::new("data data data data").unwrap();
|
/// let s = CString::new("data data data data").expect("CString::new failed");
|
||||||
/// work(&s);
|
/// work(&s);
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@@ -314,7 +314,7 @@ impl CString {
|
|||||||
///
|
///
|
||||||
/// extern { fn puts(s: *const c_char); }
|
/// extern { fn puts(s: *const c_char); }
|
||||||
///
|
///
|
||||||
/// let to_print = CString::new("Hello!").unwrap();
|
/// let to_print = CString::new("Hello!").expect("CString::new failed");
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// puts(to_print.as_ptr());
|
/// puts(to_print.as_ptr());
|
||||||
/// }
|
/// }
|
||||||
@@ -398,7 +398,7 @@ impl CString {
|
|||||||
/// fn some_extern_function(s: *mut c_char);
|
/// fn some_extern_function(s: *mut c_char);
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let c_string = CString::new("Hello!").unwrap();
|
/// let c_string = CString::new("Hello!").expect("CString::new failed");
|
||||||
/// let raw = c_string.into_raw();
|
/// let raw = c_string.into_raw();
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// some_extern_function(raw);
|
/// some_extern_function(raw);
|
||||||
@@ -428,7 +428,7 @@ impl CString {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::CString;
|
/// use std::ffi::CString;
|
||||||
///
|
///
|
||||||
/// let c_string = CString::new("foo").unwrap();
|
/// let c_string = CString::new("foo").expect("CString::new failed");
|
||||||
///
|
///
|
||||||
/// let ptr = c_string.into_raw();
|
/// let ptr = c_string.into_raw();
|
||||||
///
|
///
|
||||||
@@ -460,12 +460,12 @@ impl CString {
|
|||||||
/// use std::ffi::CString;
|
/// use std::ffi::CString;
|
||||||
///
|
///
|
||||||
/// let valid_utf8 = vec![b'f', b'o', b'o'];
|
/// let valid_utf8 = vec![b'f', b'o', b'o'];
|
||||||
/// let cstring = CString::new(valid_utf8).unwrap();
|
/// let cstring = CString::new(valid_utf8).expect("CString::new failed");
|
||||||
/// assert_eq!(cstring.into_string().unwrap(), "foo");
|
/// assert_eq!(cstring.into_string().expect("into_string() call failed"), "foo");
|
||||||
///
|
///
|
||||||
/// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o'];
|
/// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o'];
|
||||||
/// let cstring = CString::new(invalid_utf8).unwrap();
|
/// let cstring = CString::new(invalid_utf8).expect("CString::new failed");
|
||||||
/// let err = cstring.into_string().err().unwrap();
|
/// let err = cstring.into_string().err().expect("into_string().err() failed");
|
||||||
/// assert_eq!(err.utf8_error().valid_up_to(), 1);
|
/// assert_eq!(err.utf8_error().valid_up_to(), 1);
|
||||||
/// ```
|
/// ```
|
||||||
|
|
||||||
@@ -489,7 +489,7 @@ impl CString {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::CString;
|
/// use std::ffi::CString;
|
||||||
///
|
///
|
||||||
/// let c_string = CString::new("foo").unwrap();
|
/// let c_string = CString::new("foo").expect("CString::new failed");
|
||||||
/// let bytes = c_string.into_bytes();
|
/// let bytes = c_string.into_bytes();
|
||||||
/// assert_eq!(bytes, vec![b'f', b'o', b'o']);
|
/// assert_eq!(bytes, vec![b'f', b'o', b'o']);
|
||||||
/// ```
|
/// ```
|
||||||
@@ -511,7 +511,7 @@ impl CString {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::CString;
|
/// use std::ffi::CString;
|
||||||
///
|
///
|
||||||
/// let c_string = CString::new("foo").unwrap();
|
/// let c_string = CString::new("foo").expect("CString::new failed");
|
||||||
/// let bytes = c_string.into_bytes_with_nul();
|
/// let bytes = c_string.into_bytes_with_nul();
|
||||||
/// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']);
|
/// assert_eq!(bytes, vec![b'f', b'o', b'o', b'\0']);
|
||||||
/// ```
|
/// ```
|
||||||
@@ -534,7 +534,7 @@ impl CString {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::CString;
|
/// use std::ffi::CString;
|
||||||
///
|
///
|
||||||
/// let c_string = CString::new("foo").unwrap();
|
/// let c_string = CString::new("foo").expect("CString::new failed");
|
||||||
/// let bytes = c_string.as_bytes();
|
/// let bytes = c_string.as_bytes();
|
||||||
/// assert_eq!(bytes, &[b'f', b'o', b'o']);
|
/// assert_eq!(bytes, &[b'f', b'o', b'o']);
|
||||||
/// ```
|
/// ```
|
||||||
@@ -554,7 +554,7 @@ impl CString {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::CString;
|
/// use std::ffi::CString;
|
||||||
///
|
///
|
||||||
/// let c_string = CString::new("foo").unwrap();
|
/// let c_string = CString::new("foo").expect("CString::new failed");
|
||||||
/// let bytes = c_string.as_bytes_with_nul();
|
/// let bytes = c_string.as_bytes_with_nul();
|
||||||
/// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']);
|
/// assert_eq!(bytes, &[b'f', b'o', b'o', b'\0']);
|
||||||
/// ```
|
/// ```
|
||||||
@@ -573,9 +573,10 @@ impl CString {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::{CString, CStr};
|
/// use std::ffi::{CString, CStr};
|
||||||
///
|
///
|
||||||
/// let c_string = CString::new(b"foo".to_vec()).unwrap();
|
/// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
|
||||||
/// let c_str = c_string.as_c_str();
|
/// let c_str = c_string.as_c_str();
|
||||||
/// assert_eq!(c_str, CStr::from_bytes_with_nul(b"foo\0").unwrap());
|
/// assert_eq!(c_str,
|
||||||
|
/// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"));
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "as_c_str", since = "1.20.0")]
|
#[stable(feature = "as_c_str", since = "1.20.0")]
|
||||||
@@ -592,16 +593,17 @@ impl CString {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::{CString, CStr};
|
/// use std::ffi::{CString, CStr};
|
||||||
///
|
///
|
||||||
/// let c_string = CString::new(b"foo".to_vec()).unwrap();
|
/// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
|
||||||
/// let boxed = c_string.into_boxed_c_str();
|
/// let boxed = c_string.into_boxed_c_str();
|
||||||
/// assert_eq!(&*boxed, CStr::from_bytes_with_nul(b"foo\0").unwrap());
|
/// assert_eq!(&*boxed,
|
||||||
|
/// CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed"));
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "into_boxed_c_str", since = "1.20.0")]
|
#[stable(feature = "into_boxed_c_str", since = "1.20.0")]
|
||||||
pub fn into_boxed_c_str(self) -> Box<CStr> {
|
pub fn into_boxed_c_str(self) -> Box<CStr> {
|
||||||
unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) }
|
unsafe { Box::from_raw(Box::into_raw(self.into_inner()) as *mut CStr) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bypass "move out of struct which implements [`Drop`] trait" restriction.
|
/// Bypass "move out of struct which implements [`Drop`] trait" restriction.
|
||||||
///
|
///
|
||||||
/// [`Drop`]: ../ops/trait.Drop.html
|
/// [`Drop`]: ../ops/trait.Drop.html
|
||||||
fn into_inner(self) -> Box<[u8]> {
|
fn into_inner(self) -> Box<[u8]> {
|
||||||
@@ -1031,7 +1033,7 @@ impl CStr {
|
|||||||
/// use std::ffi::{CStr, CString};
|
/// use std::ffi::{CStr, CString};
|
||||||
///
|
///
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// let cstring = CString::new("hello").unwrap();
|
/// let cstring = CString::new("hello").expect("CString::new failed");
|
||||||
/// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
|
/// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
|
||||||
/// assert_eq!(cstr, &*cstring);
|
/// assert_eq!(cstr, &*cstring);
|
||||||
/// }
|
/// }
|
||||||
@@ -1058,7 +1060,7 @@ impl CStr {
|
|||||||
/// # #![allow(unused_must_use)]
|
/// # #![allow(unused_must_use)]
|
||||||
/// use std::ffi::{CString};
|
/// use std::ffi::{CString};
|
||||||
///
|
///
|
||||||
/// let ptr = CString::new("Hello").unwrap().as_ptr();
|
/// let ptr = CString::new("Hello").expect("CString::new failed").as_ptr();
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// // `ptr` is dangling
|
/// // `ptr` is dangling
|
||||||
/// *ptr;
|
/// *ptr;
|
||||||
@@ -1067,14 +1069,14 @@ impl CStr {
|
|||||||
///
|
///
|
||||||
/// This happens because the pointer returned by `as_ptr` does not carry any
|
/// This happens because the pointer returned by `as_ptr` does not carry any
|
||||||
/// lifetime information and the [`CString`] is deallocated immediately after
|
/// lifetime information and the [`CString`] is deallocated immediately after
|
||||||
/// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated.
|
/// the `CString::new("Hello").expect("CString::new failed").as_ptr()` expression is evaluated.
|
||||||
/// To fix the problem, bind the `CString` to a local variable:
|
/// To fix the problem, bind the `CString` to a local variable:
|
||||||
///
|
///
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # #![allow(unused_must_use)]
|
/// # #![allow(unused_must_use)]
|
||||||
/// use std::ffi::{CString};
|
/// use std::ffi::{CString};
|
||||||
///
|
///
|
||||||
/// let hello = CString::new("Hello").unwrap();
|
/// let hello = CString::new("Hello").expect("CString::new failed");
|
||||||
/// let ptr = hello.as_ptr();
|
/// let ptr = hello.as_ptr();
|
||||||
/// unsafe {
|
/// unsafe {
|
||||||
/// // `ptr` is valid because `hello` is in scope
|
/// // `ptr` is valid because `hello` is in scope
|
||||||
@@ -1106,7 +1108,7 @@ impl CStr {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::CStr;
|
/// use std::ffi::CStr;
|
||||||
///
|
///
|
||||||
/// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap();
|
/// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
|
||||||
/// assert_eq!(c_str.to_bytes(), b"foo");
|
/// assert_eq!(c_str.to_bytes(), b"foo");
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -1132,7 +1134,7 @@ impl CStr {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::CStr;
|
/// use std::ffi::CStr;
|
||||||
///
|
///
|
||||||
/// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap();
|
/// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
|
||||||
/// assert_eq!(c_str.to_bytes_with_nul(), b"foo\0");
|
/// assert_eq!(c_str.to_bytes_with_nul(), b"foo\0");
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
@@ -1159,7 +1161,7 @@ impl CStr {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::CStr;
|
/// use std::ffi::CStr;
|
||||||
///
|
///
|
||||||
/// let c_str = CStr::from_bytes_with_nul(b"foo\0").unwrap();
|
/// let c_str = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
|
||||||
/// assert_eq!(c_str.to_str(), Ok("foo"));
|
/// assert_eq!(c_str.to_str(), Ok("foo"));
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "cstr_to_str", since = "1.4.0")]
|
#[stable(feature = "cstr_to_str", since = "1.4.0")]
|
||||||
@@ -1200,7 +1202,8 @@ impl CStr {
|
|||||||
/// use std::borrow::Cow;
|
/// use std::borrow::Cow;
|
||||||
/// use std::ffi::CStr;
|
/// use std::ffi::CStr;
|
||||||
///
|
///
|
||||||
/// let c_str = CStr::from_bytes_with_nul(b"Hello World\0").unwrap();
|
/// let c_str = CStr::from_bytes_with_nul(b"Hello World\0")
|
||||||
|
/// .expect("CStr::from_bytes_with_nul failed");
|
||||||
/// assert_eq!(c_str.to_string_lossy(), Cow::Borrowed("Hello World"));
|
/// assert_eq!(c_str.to_string_lossy(), Cow::Borrowed("Hello World"));
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
@@ -1210,7 +1213,8 @@ impl CStr {
|
|||||||
/// use std::borrow::Cow;
|
/// use std::borrow::Cow;
|
||||||
/// use std::ffi::CStr;
|
/// use std::ffi::CStr;
|
||||||
///
|
///
|
||||||
/// let c_str = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0").unwrap();
|
/// let c_str = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0")
|
||||||
|
/// .expect("CStr::from_bytes_with_nul failed");
|
||||||
/// assert_eq!(
|
/// assert_eq!(
|
||||||
/// c_str.to_string_lossy(),
|
/// c_str.to_string_lossy(),
|
||||||
/// Cow::Owned(String::from("Hello <20>World")) as Cow<str>
|
/// Cow::Owned(String::from("Hello <20>World")) as Cow<str>
|
||||||
@@ -1231,9 +1235,9 @@ impl CStr {
|
|||||||
/// ```
|
/// ```
|
||||||
/// use std::ffi::CString;
|
/// use std::ffi::CString;
|
||||||
///
|
///
|
||||||
/// let c_string = CString::new(b"foo".to_vec()).unwrap();
|
/// let c_string = CString::new(b"foo".to_vec()).expect("CString::new failed");
|
||||||
/// let boxed = c_string.into_boxed_c_str();
|
/// let boxed = c_string.into_boxed_c_str();
|
||||||
/// assert_eq!(boxed.into_c_string(), CString::new("foo").unwrap());
|
/// assert_eq!(boxed.into_c_string(), CString::new("foo").expect("CString::new failed"));
|
||||||
/// ```
|
/// ```
|
||||||
#[stable(feature = "into_boxed_c_str", since = "1.20.0")]
|
#[stable(feature = "into_boxed_c_str", since = "1.20.0")]
|
||||||
pub fn into_c_string(self: Box<CStr>) -> CString {
|
pub fn into_c_string(self: Box<CStr>) -> CString {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
use std::cmp;
|
use std::cmp;
|
||||||
use symbol::Symbol;
|
use symbol::Symbol;
|
||||||
|
|
||||||
/// To find the Levenshtein distance between two strings
|
/// Find the Levenshtein distance between two strings
|
||||||
pub fn lev_distance(a: &str, b: &str) -> usize {
|
pub fn lev_distance(a: &str, b: &str) -> usize {
|
||||||
// cases which don't require further computation
|
// cases which don't require further computation
|
||||||
if a.is_empty() {
|
if a.is_empty() {
|
||||||
@@ -41,10 +41,12 @@ pub fn lev_distance(a: &str, b: &str) -> usize {
|
|||||||
} dcol[t_last + 1]
|
} dcol[t_last + 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// To find the best match for a given string from an iterator of names
|
/// Find the best match for a given word in the given iterator
|
||||||
|
///
|
||||||
/// As a loose rule to avoid the obviously incorrect suggestions, it takes
|
/// As a loose rule to avoid the obviously incorrect suggestions, it takes
|
||||||
/// an optional limit for the maximum allowable edit distance, which defaults
|
/// an optional limit for the maximum allowable edit distance, which defaults
|
||||||
/// to one-third of the given word.
|
/// to one-third of the given word.
|
||||||
|
///
|
||||||
/// Besides Levenshtein, we use case insensitive comparison to improve accuracy on an edge case with
|
/// Besides Levenshtein, we use case insensitive comparison to improve accuracy on an edge case with
|
||||||
/// a lower(upper)case letters mismatch.
|
/// a lower(upper)case letters mismatch.
|
||||||
pub fn find_best_match_for_name<'a, T>(iter_names: T,
|
pub fn find_best_match_for_name<'a, T>(iter_names: T,
|
||||||
@@ -105,3 +107,39 @@ fn test_lev_distance() {
|
|||||||
assert_eq!(lev_distance(b, c), 1);
|
assert_eq!(lev_distance(b, c), 1);
|
||||||
assert_eq!(lev_distance(c, b), 1);
|
assert_eq!(lev_distance(c, b), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_find_best_match_for_name() {
|
||||||
|
use with_globals;
|
||||||
|
with_globals(|| {
|
||||||
|
let input = vec![Symbol::intern("aaab"), Symbol::intern("aaabc")];
|
||||||
|
assert_eq!(
|
||||||
|
find_best_match_for_name(input.iter(), "aaaa", None),
|
||||||
|
Some(Symbol::intern("aaab"))
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
find_best_match_for_name(input.iter(), "1111111111", None),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
|
||||||
|
let input = vec![Symbol::intern("aAAA")];
|
||||||
|
assert_eq!(
|
||||||
|
find_best_match_for_name(input.iter(), "AAAA", None),
|
||||||
|
Some(Symbol::intern("aAAA"))
|
||||||
|
);
|
||||||
|
|
||||||
|
let input = vec![Symbol::intern("AAAA")];
|
||||||
|
// Returns None because `lev_distance > max_dist / 3`
|
||||||
|
assert_eq!(
|
||||||
|
find_best_match_for_name(input.iter(), "aaaa", None),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
|
||||||
|
let input = vec![Symbol::intern("AAAA")];
|
||||||
|
assert_eq!(
|
||||||
|
find_best_match_for_name(input.iter(), "aaaa", Some(4)),
|
||||||
|
Some(Symbol::intern("AAAA"))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
# source tarball for a stable release you'll likely see `1.x.0` for rustc and
|
# source tarball for a stable release you'll likely see `1.x.0` for rustc and
|
||||||
# `0.x.0` for Cargo where they were released on `date`.
|
# `0.x.0` for Cargo where they were released on `date`.
|
||||||
|
|
||||||
date: 2018-08-01
|
date: 2018-09-11
|
||||||
rustc: beta
|
rustc: beta
|
||||||
cargo: beta
|
cargo: beta
|
||||||
|
|
||||||
|
|||||||
@@ -16,11 +16,11 @@ all:
|
|||||||
$(RUSTC) -C extra-filename=foo dummy.rs 2>&1
|
$(RUSTC) -C extra-filename=foo dummy.rs 2>&1
|
||||||
#Option taking no argument
|
#Option taking no argument
|
||||||
$(RUSTC) -C lto= dummy.rs 2>&1 | \
|
$(RUSTC) -C lto= dummy.rs 2>&1 | \
|
||||||
$(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or'
|
$(CGREP) 'codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted'
|
||||||
$(RUSTC) -C lto=1 dummy.rs 2>&1 | \
|
$(RUSTC) -C lto=1 dummy.rs 2>&1 | \
|
||||||
$(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or'
|
$(CGREP) 'codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted'
|
||||||
$(RUSTC) -C lto=foo dummy.rs 2>&1 | \
|
$(RUSTC) -C lto=foo dummy.rs 2>&1 | \
|
||||||
$(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or'
|
$(CGREP) 'codegen option `lto` - either a boolean (`yes`, `no`, `on`, `off`, etc), `thin`, `fat`, or omitted'
|
||||||
$(RUSTC) -C lto dummy.rs
|
$(RUSTC) -C lto dummy.rs
|
||||||
|
|
||||||
# Should not link dead code...
|
# Should not link dead code...
|
||||||
|
|||||||
@@ -1,6 +1,30 @@
|
|||||||
-include ../tools.mk
|
-include ../tools.mk
|
||||||
|
|
||||||
all:
|
all: noparam bool_true bool_false thin fat
|
||||||
|
|
||||||
|
noparam:
|
||||||
$(RUSTC) lib.rs
|
$(RUSTC) lib.rs
|
||||||
$(RUSTC) main.rs -C lto
|
$(RUSTC) main.rs -C lto
|
||||||
$(call RUN,main)
|
$(call RUN,main)
|
||||||
|
|
||||||
|
bool_true:
|
||||||
|
$(RUSTC) lib.rs
|
||||||
|
$(RUSTC) main.rs -C lto=yes
|
||||||
|
$(call RUN,main)
|
||||||
|
|
||||||
|
|
||||||
|
bool_false:
|
||||||
|
$(RUSTC) lib.rs
|
||||||
|
$(RUSTC) main.rs -C lto=off
|
||||||
|
$(call RUN,main)
|
||||||
|
|
||||||
|
thin:
|
||||||
|
$(RUSTC) lib.rs
|
||||||
|
$(RUSTC) main.rs -C lto=thin
|
||||||
|
$(call RUN,main)
|
||||||
|
|
||||||
|
fat:
|
||||||
|
$(RUSTC) lib.rs
|
||||||
|
$(RUSTC) main.rs -C lto=fat
|
||||||
|
$(call RUN,main)
|
||||||
|
|
||||||
|
|||||||
37
src/test/ui/consts/const-eval/mod-static-with-const-fn.rs
Normal file
37
src/test/ui/consts/const-eval/mod-static-with-const-fn.rs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// New test for #53818: modifying static memory at compile-time is not allowed.
|
||||||
|
// The test should never succeed.
|
||||||
|
|
||||||
|
#![feature(const_raw_ptr_deref)]
|
||||||
|
#![feature(const_let)]
|
||||||
|
|
||||||
|
use std::cell::UnsafeCell;
|
||||||
|
|
||||||
|
struct Foo(UnsafeCell<u32>);
|
||||||
|
|
||||||
|
unsafe impl Send for Foo {}
|
||||||
|
unsafe impl Sync for Foo {}
|
||||||
|
|
||||||
|
static FOO: Foo = Foo(UnsafeCell::new(42));
|
||||||
|
|
||||||
|
static BAR: () = unsafe {
|
||||||
|
*FOO.0.get() = 5;
|
||||||
|
//~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||||
|
|
||||||
|
// This error is caused by a separate bug that the feature gate error is reported
|
||||||
|
// even though the feature gate "const_let" is active.
|
||||||
|
//~| statements in statics are unstable (see issue #48821)
|
||||||
|
};
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("{}", unsafe { *FOO.0.get() });
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants
|
||||||
|
--> $DIR/mod-static-with-const-fn.rs:27:6
|
||||||
|
|
|
||||||
|
LL | *FOO.0.get() = 5;
|
||||||
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
|
error[E0658]: statements in statics are unstable (see issue #48821)
|
||||||
|
--> $DIR/mod-static-with-const-fn.rs:27:5
|
||||||
|
|
|
||||||
|
LL | *FOO.0.get() = 5;
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= help: add #![feature(const_let)] to the crate attributes to enable
|
||||||
|
|
||||||
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
Some errors occurred: E0015, E0658.
|
||||||
|
For more information about an error, try `rustc --explain E0015`.
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// ignore-musl
|
||||||
|
// ignore-x86
|
||||||
// error-pattern: cycle detected
|
// error-pattern: cycle detected
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
|
|||||||
28
src/test/ui/elide-errors-on-mismatched-tuple.rs
Normal file
28
src/test/ui/elide-errors-on-mismatched-tuple.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
// Hide irrelevant E0277 errors (#50333)
|
||||||
|
|
||||||
|
trait T {}
|
||||||
|
|
||||||
|
struct A;
|
||||||
|
impl T for A {}
|
||||||
|
impl A {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (a, b, c) = (A::new(), A::new()); // This tuple is 2 elements, should be three
|
||||||
|
//~^ ERROR mismatched types
|
||||||
|
let ts: Vec<&T> = vec![&a, &b, &c];
|
||||||
|
// There is no E0277 error above, as `a`, `b` and `c` are `TyErr`
|
||||||
|
}
|
||||||
12
src/test/ui/elide-errors-on-mismatched-tuple.stderr
Normal file
12
src/test/ui/elide-errors-on-mismatched-tuple.stderr
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/elide-errors-on-mismatched-tuple.rs:24:9
|
||||||
|
|
|
||||||
|
LL | let (a, b, c) = (A::new(), A::new()); // This tuple is 2 elements, should be three
|
||||||
|
| ^^^^^^^^^ expected a tuple with 2 elements, found one with 3 elements
|
||||||
|
|
|
||||||
|
= note: expected type `(A, A)`
|
||||||
|
found type `(_, _, _)`
|
||||||
|
|
||||||
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
||||||
@@ -8,6 +8,9 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
// ignore-musl
|
||||||
|
// ignore-x86
|
||||||
|
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
trait Foo {
|
trait Foo {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
error[E0643]: method `foo` has incompatible signature for trait
|
error[E0643]: method `foo` has incompatible signature for trait
|
||||||
--> $DIR/impl-generic-mismatch.rs:18:12
|
--> $DIR/impl-generic-mismatch.rs:21:12
|
||||||
|
|
|
|
||||||
LL | fn foo(&self, _: &impl Debug);
|
LL | fn foo(&self, _: &impl Debug);
|
||||||
| ---------- declaration in trait here
|
| ---------- declaration in trait here
|
||||||
@@ -12,7 +12,7 @@ LL | fn foo(&self, _: &impl Debug) { }
|
|||||||
| -- ^^^^^^^^^^
|
| -- ^^^^^^^^^^
|
||||||
|
|
||||||
error[E0643]: method `bar` has incompatible signature for trait
|
error[E0643]: method `bar` has incompatible signature for trait
|
||||||
--> $DIR/impl-generic-mismatch.rs:27:23
|
--> $DIR/impl-generic-mismatch.rs:30:23
|
||||||
|
|
|
|
||||||
LL | fn bar<U: Debug>(&self, _: &U);
|
LL | fn bar<U: Debug>(&self, _: &U);
|
||||||
| - declaration in trait here
|
| - declaration in trait here
|
||||||
@@ -25,7 +25,7 @@ LL | fn bar<U: Debug>(&self, _: &U) { }
|
|||||||
| ^^^^^^^^^^ ^
|
| ^^^^^^^^^^ ^
|
||||||
|
|
||||||
error[E0643]: method `hash` has incompatible signature for trait
|
error[E0643]: method `hash` has incompatible signature for trait
|
||||||
--> $DIR/impl-generic-mismatch.rs:38:33
|
--> $DIR/impl-generic-mismatch.rs:41:33
|
||||||
|
|
|
|
||||||
LL | fn hash(&self, hasher: &mut impl Hasher) {}
|
LL | fn hash(&self, hasher: &mut impl Hasher) {}
|
||||||
| ^^^^^^^^^^^ expected generic parameter, found `impl Trait`
|
| ^^^^^^^^^^^ expected generic parameter, found `impl Trait`
|
||||||
|
|||||||
Reference in New Issue
Block a user