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:
bors
2018-09-13 22:40:35 +00:00
38 changed files with 398 additions and 113 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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[..],
) )

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View 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`
}

View 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`.

View File

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

View File

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