script:
MESSAGE_FILE=$(mktemp -t msg.XXXXXX);
. src/ci/docker/x86_64-gnu-tools/repo.sh;
- commit_toolstate_change "$MESSAGE_FILE" "$TRAVIS_BUILD_DIR/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE"
+ commit_toolstate_change "$MESSAGE_FILE" "$TRAVIS_BUILD_DIR/src/tools/publish_toolstate.py" "$(git rev-parse HEAD)" "$(git log --format=%s -n1 HEAD)" "$MESSAGE_FILE" "$TOOLSTATE_REPO_ACCESS_TOKEN";
env:
global:
[IRC]: https://en.wikipedia.org/wiki/Internet_Relay_Chat
[#rust]: irc://irc.mozilla.org/rust
[#rust-beginners]: irc://irc.mozilla.org/rust-beginners
-[rustc-guide]: https://rust-lang-nursery.github.io/rustc-guide/about-this-guide.html
+[rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/about-this-guide.html
## License
[license]: #license
name = "arena"
version = "0.0.0"
+[[package]]
+name = "arrayvec"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "atty"
version = "0.2.6"
"cc 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
-[[package]]
-name = "coco"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
[[package]]
name = "commoncrypto"
version = "0.2.0"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
+[[package]]
+name = "crossbeam-deque"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "crossbeam-epoch 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
+ "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
[[package]]
name = "crypto-hash"
version = "0.3.0"
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "memoffset"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "miniz-sys"
version = "0.1.10"
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
+[[package]]
+name = "nodrop"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
[[package]]
name = "num"
version = "0.1.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "rayon"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "either 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rayon-core"
-version = "1.3.0"
+version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rls"
-version = "0.125.0"
+version = "0.126.0"
dependencies = [
"cargo 0.26.0",
+ "cargo_metadata 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
- "rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-analysis 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-analysis 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rustfmt-nightly 0.3.8",
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rls-analysis"
-version = "0.11.0"
+version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"derive-new 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
[[package]]
name = "rls-vfs"
-version = "0.4.4"
+version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"racer 2.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
"checksum ar 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "35c7a5669cb64f085739387e1308b74e6d44022464b7f1b63bbd4ceb6379ec31"
+"checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef"
"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859"
"checksum backtrace 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbbf59b1c43eefa8c3ede390fcc36820b4999f7914104015be25025e0d62af2"
"checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661"
"checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f"
"checksum clippy_lints 0.0.186 (registry+https://github.com/rust-lang/crates.io-index)" = "a3864104a4e6092e644b985dd7543e5f24e99aa7262f5ee400bcb17cfeec1bf5"
"checksum cmake 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "56d741ea7a69e577f6d06b36b7dff4738f680593dc27a701ffa8506b73ce28bb"
-"checksum coco 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c06169f5beb7e31c7c67ebf5540b8b472d23e3eade3b2ec7d1f5b504a85f91bd"
"checksum commoncrypto 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d056a8586ba25a1e4d61cb090900e495952c7886786fc55f909ab2f819b69007"
"checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2"
"checksum compiletest_rs 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6c5aafb5d4a77c6b5fa384fe93c7a9a3561bd88c4b8b8e45187cf5e779b1badc"
"checksum core-foundation-sys 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "152195421a2e6497a8179195672e9d4ee8e45ed8c465b626f1606d27a08ebcd5"
"checksum crossbeam 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "bd66663db5a988098a89599d4857919b3acf7f61402e61365acfd3919857b9be"
"checksum crossbeam 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "24ce9782d4d5c53674646a6a4c1863a21a8fc0cb649b3c94dfc16e45071dea19"
+"checksum crossbeam-deque 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f739f8c5363aca78cfb059edf753d8f0d36908c348f3d8d1503f03d8b75d9cf3"
+"checksum crossbeam-epoch 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "59796cc6cbbdc6bb319161349db0c3250ec73ec7fcb763a51065ec4e2e158552"
+"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9"
"checksum crypto-hash 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "34903878eec1694faf53cae8473a088df333181de421d4d3d48061d6559fe602"
"checksum curl 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b70fd6394677d3c0e239ff4be6f2b3176e171ffd1c23ffdc541e78dea2b8bb5e"
"checksum curl-sys 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f46e49c7125131f5afaded06944d6888b55cbdf8eba05dae73c954019b907961"
"checksum mdbook 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fef236caad7ba3b5b3944df946f19ab3e190bca53c111dd00fe05fa8d879f2fd"
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
+"checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3"
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)" = "3a80f842784ef6c9a958b68b7516bc7e35883c614004dd94959a4dca1b716c09"
"checksum nibble_vec 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "62e678237a4c70c5f2b917cefd7d080dfbf800421f06e8a59d4e28ef5130fd9e"
"checksum nix 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "47e49f6982987135c5e9620ab317623e723bd06738fd85377e8d55f57c8b6487"
+"checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2"
"checksum num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4083e14b542ea3eb9b5f33ff48bd373a92d78687e74f4cc0a30caeb754f0ca"
"checksum num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "bdc1494b5912f088f260b775799468d9b9209ac60885d8186a547a0476289e23"
"checksum num-complex 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "58de7b4bf7cf5dbecb635a5797d489864eadd03b107930cbccf9e0fd7428b47c"
"checksum radix_trie 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "211c49b6a9995cac0fd1dd9ca60b42cf3a51e151a12eb954b3a9e75513426ee8"
"checksum rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)" = "512870020642bb8c221bf68baa1b2573da814f6ccfe5c9699b1c303047abe9b1"
"checksum rayon 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed02d09394c94ffbdfdc755ad62a132e94c3224a8354e78a1200ced34df12edf"
-"checksum rayon-core 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e64b609139d83da75902f88fd6c01820046840a18471e4dfcd5ac7c0f46bea53"
+"checksum rayon 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "485541959c8ecc49865526fe6c4de9653dd6e60d829d6edf0be228167b60372d"
+"checksum rayon-core 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d24ad214285a7729b174ed6d3bcfcb80177807f959d95fafd5bfc5c4f201ac8"
"checksum redox_syscall 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "0d92eecebad22b767915e4d529f89f28ee96dbbf5a4810d2b844373f136417fd"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
-"checksum rls-analysis 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "30b08808959205a5cf23c68ace2d9d6defdd6867f3cd5d62981cf50fb52f8882"
+"checksum rls-analysis 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "39461c31c9ec26c2f15821d6aaa349216bf71e24e69550d9f8eeded78dc435e1"
"checksum rls-blacklist 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56fb7b8e4850b988fbcf277fbdb1eff36879070d02fc1ca243b559273866973d"
"checksum rls-data 0.15.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bea04462e94b5512a78499837eecb7db182ff082144cd1b4bc32ef5d43de6510"
"checksum rls-rustc 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "85cfb9dde19e313da3e47738008f8a472e470cc42d910b71595a9238494701f2"
"checksum rls-span 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d7c7046dc6a92f2ae02ed302746db4382e75131b9ce20ce967259f6b5867a6a"
-"checksum rls-vfs 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ffd34691a510938bb67fe0444fb363103c73ffb31c121d1e16bc92d8945ea8ff"
+"checksum rls-vfs 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be231e1e559c315bc60ced5ad2cc2d7a9c208ed7d4e2c126500149836fda19bb"
"checksum rustc-ap-rustc_cratesio_shim 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ad5e562044ea78a6764dd75ae8afe4b21fde49f4548024b5fdf6345c21fb524"
"checksum rustc-ap-rustc_data_structures 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c0d65325492aba7db72899e3edbab34d39af98c42ab7c7e450c9a288ffe4ad"
"checksum rustc-ap-rustc_errors 29.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "87d4ab2e06a671b5b5c5b0359dac346f164c99d059dce6a22feb08f2f56bd182"
paths: BTreeSet<PathSet>,
// If this is a default rule, this is an additional constraint placed on
- // it's run. Generally something like compiler docs being enabled.
+ // its run. Generally something like compiler docs being enabled.
is_really_default: bool,
}
test::RunPassPretty, test::RunFailPretty, test::RunPassValgrindPretty,
test::RunPassFullDepsPretty, test::RunFailFullDepsPretty, test::RunMake,
test::Crate, test::CrateLibrustc, test::Rustdoc, test::Linkcheck, test::Cargotest,
- test::Cargo, test::Rls, test::Docs, test::ErrorIndex, test::Distcheck,
+ test::Cargo, test::Rls, test::ErrorIndex, test::Distcheck,
+ test::Nomicon, test::Reference, test::RustdocBook, test::RustByExample,
+ test::TheBook, test::UnstableBook,
test::Rustfmt, test::Miri, test::Clippy, test::RustdocJS, test::RustdocTheme),
Kind::Bench => describe!(test::Crate, test::CrateLibrustc),
Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
.arg(build.src.join("src/librustc_trans/Cargo.toml"));
rustc_cargo_env(build, &mut cargo);
+ let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
+
match &*self.backend {
"llvm" | "emscripten" => {
// Build LLVM for our target. This will implicitly build the
features.push_str(" emscripten");
}
- let _folder = build.fold_output(|| format!("stage{}-rustc_trans", compiler.stage));
println!("Building stage{} codegen artifacts ({} -> {}, {})",
compiler.stage, &compiler.host, target, self.backend);
true
}
-fn try_run_quiet(build: &Build, cmd: &mut Command) {
+fn try_run_quiet(build: &Build, cmd: &mut Command) -> bool {
if !build.fail_fast {
if !build.try_run_quiet(cmd) {
let mut failures = build.delayed_failures.borrow_mut();
failures.push(format!("{:?}", cmd));
+ return false;
}
} else {
build.run_quiet(cmd);
}
+ true
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub struct Docs {
+struct DocTest {
compiler: Compiler,
+ path: &'static str,
+ name: &'static str,
+ is_ext_doc: bool,
}
-impl Step for Docs {
+impl Step for DocTest {
type Output = ();
- const DEFAULT: bool = true;
const ONLY_HOSTS: bool = true;
fn should_run(run: ShouldRun) -> ShouldRun {
- run.path("src/doc")
- }
-
- fn make_run(run: RunConfig) {
- run.builder.ensure(Docs {
- compiler: run.builder.compiler(run.builder.top_stage, run.host),
- });
+ run.never()
}
/// Run `rustdoc --test` for all documentation in `src/doc`.
// Do a breadth-first traversal of the `src/doc` directory and just run
// tests for all files that end in `*.md`
- let mut stack = vec![build.src.join("src/doc")];
+ let mut stack = vec![build.src.join(self.path)];
let _time = util::timeit();
- let _folder = build.fold_output(|| "test_docs");
+ let _folder = build.fold_output(|| format!("test_{}", self.name));
while let Some(p) = stack.pop() {
if p.is_dir() {
continue;
}
- markdown_test(builder, compiler, &p);
+ let test_result = markdown_test(builder, compiler, &p);
+ if self.is_ext_doc {
+ let toolstate = if test_result {
+ ToolState::TestPass
+ } else {
+ ToolState::TestFail
+ };
+ build.save_toolstate(self.name, toolstate);
+ }
}
}
}
+macro_rules! test_book {
+ ($($name:ident, $path:expr, $book_name:expr, default=$default:expr;)+) => {
+ $(
+ #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+ pub struct $name {
+ compiler: Compiler,
+ }
+
+ impl Step for $name {
+ type Output = ();
+ const DEFAULT: bool = $default;
+ const ONLY_HOSTS: bool = true;
+
+ fn should_run(run: ShouldRun) -> ShouldRun {
+ run.path($path)
+ }
+
+ fn make_run(run: RunConfig) {
+ run.builder.ensure($name {
+ compiler: run.builder.compiler(run.builder.top_stage, run.host),
+ });
+ }
+
+ fn run(self, builder: &Builder) {
+ builder.ensure(DocTest {
+ compiler: self.compiler,
+ path: $path,
+ name: $book_name,
+ is_ext_doc: !$default,
+ });
+ }
+ }
+ )+
+ }
+}
+
+test_book!(
+ Nomicon, "src/doc/nomicon", "nomicon", default=false;
+ Reference, "src/doc/reference", "reference", default=false;
+ RustdocBook, "src/doc/rustdoc", "rustdoc", default=true;
+ RustByExample, "src/doc/rust-by-example", "rust-by-example", default=false;
+ TheBook, "src/doc/book", "book", default=false;
+ UnstableBook, "src/doc/unstable-book", "unstable-book", default=true;
+);
+
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub struct ErrorIndex {
compiler: Compiler,
}
}
-fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) {
+fn markdown_test(builder: &Builder, compiler: Compiler, markdown: &Path) -> bool {
let build = builder.build;
let mut file = t!(File::open(markdown));
let mut contents = String::new();
t!(file.read_to_string(&mut contents));
if !contents.contains("```") {
- return;
+ return true;
}
println!("doc tests for: {}", markdown.display());
cmd.arg("--test-args").arg(test_args);
if build.config.quiet_tests {
- try_run_quiet(build, &mut cmd);
+ try_run_quiet(build, &mut cmd)
} else {
- try_run(build, &mut cmd);
+ try_run(build, &mut cmd)
}
}
COPY scripts/sccache.sh /scripts/
RUN sh /scripts/sccache.sh
+COPY x86_64-gnu-tools/checkregression.py /tmp/
COPY x86_64-gnu-tools/checktools.sh /tmp/
COPY x86_64-gnu-tools/repo.sh /tmp/
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+# 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.
+
+import sys
+import json
+
+if __name__ == '__main__':
+ os_name = sys.argv[1]
+ toolstate_file = sys.argv[2]
+ current_state = sys.argv[3]
+
+ with open(toolstate_file, 'r') as f:
+ toolstate = json.load(f)
+ with open(current_state, 'r') as f:
+ current = json.load(f)
+
+ regressed = False
+ for cur in current:
+ tool = cur['tool']
+ state = cur[os_name]
+ new_state = toolstate.get(tool, '')
+ if new_state < state:
+ print(
+ 'Error: The state of "{}" has regressed from "{}" to "{}"'
+ .format(tool, state, new_state)
+ )
+ regressed = True
+
+ if regressed:
+ sys.exit(1)
OS="$3"
COMMIT="$(git rev-parse HEAD)"
CHANGED_FILES="$(git diff --name-status HEAD HEAD^)"
+SIX_WEEK_CYCLE="$(( ($(date +%s) / 604800 - 3) % 6 ))"
+# ^ 1970 Jan 1st is a Thursday, and our release dates are also on Thursdays,
+# thus we could divide by 604800 (7 days in seconds) directly.
touch "$TOOLSTATE_FILE"
set +e
python2.7 "$X_PY" test --no-fail-fast \
+ src/doc/book \
+ src/doc/nomicon \
+ src/doc/reference \
+ src/doc/rust-by-example \
src/tools/rls \
src/tools/rustfmt \
src/tools/miri \
set -e
cat "$TOOLSTATE_FILE"
+echo
-# If this PR is intended to update one of these tools, do not let the build pass
-# when they do not test-pass.
-for TOOL in rls rustfmt clippy; do
- echo "Verifying status of $TOOL..."
- if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]src/tools/$TOOL$"; then
- echo "This PR updated 'src/tools/$TOOL', verifying if status is 'test-pass'..."
- if grep -vq '"'"$TOOL"'[^"]*":"test-pass"' "$TOOLSTATE_FILE"; then
+verify_status() {
+ echo "Verifying status of $1..."
+ if echo "$CHANGED_FILES" | grep -q "^M[[:blank:]]$2$"; then
+ echo "This PR updated '$2', verifying if status is 'test-pass'..."
+ if grep -vq '"'"$1"'":"test-pass"' "$TOOLSTATE_FILE"; then
echo
- echo "โ ๏ธ We detected that this PR updated '$TOOL', but its tests failed."
+ echo "โ ๏ธ We detected that this PR updated '$1', but its tests failed."
echo
- echo "If you do intend to update '$TOOL', please check the error messages above and"
+ echo "If you do intend to update '$1', please check the error messages above and"
echo "commit another update."
echo
- echo "If you do NOT intend to update '$TOOL', please ensure you did not accidentally"
- echo "change the submodule at 'src/tools/$TOOL'. You may ask your reviewer for the"
+ echo "If you do NOT intend to update '$1', please ensure you did not accidentally"
+ echo "change the submodule at '$2'. You may ask your reviewer for the"
echo "proper steps."
exit 3
fi
fi
-done
+}
+
+# If this PR is intended to update one of these tools, do not let the build pass
+# when they do not test-pass.
+
+verify_status book src/doc/book
+verify_status nomicon src/doc/nomicon
+verify_status reference src/doc/reference
+verify_status rust-by-example src/doc/rust-by-example
+verify_status rls src/tool/rls
+verify_status rustfmt src/tool/rustfmt
+verify_status clippy-driver src/tool/clippy
+#verify_status miri src/tool/miri
if [ "$RUST_RELEASE_CHANNEL" = nightly -a -n "${TOOLSTATE_REPO_ACCESS_TOKEN+is_set}" ]; then
. "$(dirname $0)/repo.sh"
sed -i "1 a\\
$COMMIT\t$(cat "$TOOLSTATE_FILE")
" "history/$OS.tsv"
+ # if we are at the last week in the 6-week release cycle, reject any kind of regression.
+ if [ $SIX_WEEK_CYCLE -eq 5 ]; then
+ python2.7 "$(dirname $0)/checkregression.py" \
+ "$OS" "$TOOLSTATE_FILE" "rust-toolstate/_data/latest.json"
+ fi
rm -f "$MESSAGE_FILE"
exit 0
fi
\fB\-v\fR, \fB\-\-verbose\fR
Use verbose output.
.TP
+\fB\-\-remap\-path\-prefix\fR \fIfrom\fR=\fIto\fR
+Remap source path prefixes in all output, including compiler diagnostics, debug information,
+macro expansions, etc. The \fIfrom\fR=\fIto\fR parameter is scanned from right to left, so \fIfrom\fR
+may contain '=', but \fIto\fR may not.
+
+This is useful for normalizing build products, for example by removing the current directory out of
+pathnames emitted into the object files. The replacement is purely textual, with no consideration of
+the current system's pathname syntax. For example \fI\-\-remap\-path\-prefix foo=bar\fR will
+match \fBfoo/lib.rs\fR but not \fB./foo/lib.rs\fR.
+.TP
\fB\-\-extern\fR \fINAME\fR=\fIPATH\fR
Specify where an external rust library is located. These should match
\fIextern\fR declarations in the crate's source code.
+++ /dev/null
-# `remap-path-prefix`
-
-The tracking issue for this feature is: [#41555](https://github.com/rust-lang/rust/issues/41555)
-
-------------------------
-
-The `-Z remap-path-prefix-from`, `-Z remap-path-prefix-to` commandline option
-pair allows to replace prefixes of any file paths the compiler emits in various
-places. This is useful for bringing debuginfo paths into a well-known form and
-for achieving reproducible builds independent of the directory the compiler was
-executed in. All paths emitted by the compiler are affected, including those in
-error messages.
-
-In order to map all paths starting with `/home/foo/my-project/src` to
-`/sources/my-project`, one would invoke the compiler as follows:
-
-```text
-rustc -Zremap-path-prefix-from="/home/foo/my-project/src" -Zremap-path-prefix-to="/sources/my-project"
-```
-
-Debuginfo for code from the file `/home/foo/my-project/src/foo/mod.rs`,
-for example, would then point debuggers to `/sources/my-project/foo/mod.rs`
-instead of the original file.
-
-The options can be specified multiple times when multiple prefixes should be
-mapped:
-
-```text
-rustc -Zremap-path-prefix-from="/home/foo/my-project/src" \
- -Zremap-path-prefix-to="/sources/my-project" \
- -Zremap-path-prefix-from="/home/foo/my-project/build-dir" \
- -Zremap-path-prefix-to="/stable-build-dir"
-```
-
-When the options are given multiple times, the nth `-from` will be matched up
-with the nth `-to` and they can appear anywhere on the commandline. Mappings
-specified later on the line will take precedence over earlier ones.
/// assert_eq!(merged, "alphabetagamma");
/// ```
///
- /// You can also rewrite this in terms of [`flat_map()`] which is preferable
- /// in this case since that conveys intent clearer:
+ /// You can also rewrite this in terms of [`flat_map()`], which is preferable
+ /// in this case since it conveys intent more clearly:
///
/// ```
/// let words = ["alpha", "beta", "gamma"];
#[allow(improper_ctypes)]
extern {
#[lang = "panic_fmt"]
- #[unwind]
+ #[cfg_attr(stage0, unwind)]
+ #[cfg_attr(not(stage0), unwind(allowed))]
fn panic_impl(fmt: fmt::Arguments, file: &'static str, line: u32, col: u32) -> !;
}
let (file, line, col) = *file_line_col;
// See docs in the `unwind` module.
#[cfg(all(target_os="windows", target_arch = "x86", target_env="gnu"))]
#[lang = "eh_unwind_resume"]
-#[unwind]
+#[cfg_attr(stage0, unwind)]
+#[cfg_attr(not(stage0), unwind(allowed))]
unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: *mut u8) -> ! {
uw::_Unwind_Resume(panic_ctx as *mut uw::_Unwind_Exception);
}
// Entry point for raising an exception, just delegates to the platform-specific
// implementation.
#[no_mangle]
-#[unwind]
+#[cfg_attr(stage0, unwind)]
+#[cfg_attr(not(stage0), unwind(allowed))]
pub unsafe extern "C" fn __rust_start_panic(data: usize, vtable: usize) -> u32 {
imp::panic(mem::transmute(raw::TraitObject {
data: data as *mut (),
}
#[lang = "eh_unwind_resume"]
-#[unwind]
+#[cfg_attr(stage0, unwind)]
+#[cfg_attr(not(stage0), unwind(allowed))]
unsafe extern "C" fn rust_eh_unwind_resume(panic_ctx: c::LPVOID) -> ! {
let params = [panic_ctx as c::ULONG_PTR];
c::RaiseException(RUST_PANIC,
pub use self::EXCEPTION_DISPOSITION::*;
extern "system" {
- #[unwind]
+ #[cfg_attr(stage0, unwind)]
+ #[cfg_attr(not(stage0), unwind(allowed))]
pub fn RaiseException(dwExceptionCode: DWORD,
dwExceptionFlags: DWORD,
nNumberOfArguments: DWORD,
lpArguments: *const ULONG_PTR);
- #[unwind]
+ #[cfg_attr(stage0, unwind)]
+ #[cfg_attr(not(stage0), unwind(allowed))]
pub fn RtlUnwindEx(TargetFrame: LPVOID,
TargetIp: LPVOID,
ExceptionRecord: *const EXCEPTION_RECORD,
ReturnValue: LPVOID,
OriginalContext: *const CONTEXT,
HistoryTable: *const UNWIND_HISTORY_TABLE);
- #[unwind]
+ #[cfg_attr(stage0, unwind)]
+ #[cfg_attr(not(stage0), unwind(allowed))]
pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8);
}
/// If the code span associated with this `SourceFile` was generated by an external macro, this
/// may not be an actual path on the filesystem. Use [`is_real`] to check.
///
- /// Also note that even if `is_real` returns `true`, if `-Z remap-path-prefix-*` was passed on
+ /// Also note that even if `is_real` returns `true`, if `--remap-path-prefix` was passed on
/// the command line, the path as given may not actually be valid.
///
/// [`is_real`]: #method.is_real
use hir::map::{Definitions, DefKey, DefPathData};
use hir::def_id::{DefIndex, DefId, CRATE_DEF_INDEX, DefIndexAddressSpace};
use hir::def::{Def, PathResolution};
-use lint::builtin::PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES;
+use lint::builtin::{self, PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES};
use middle::cstore::CrateStore;
use rustc_data_structures::indexed_vec::IndexVec;
use session::Session;
TyKind::Path(ref qself, ref path) => {
let id = self.lower_node_id(t.id);
let qpath = self.lower_qpath(t.id, qself, path, ParamMode::Explicit, itctx);
- return self.ty_path(id, t.span, qpath);
+ let ty = self.ty_path(id, t.span, qpath);
+ if let hir::TyTraitObject(..) = ty.node {
+ self.maybe_lint_bare_trait(t.span, t.id, qself.is_none() && path.is_global());
+ }
+ return ty;
}
TyKind::ImplicitSelf => {
hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
let expr = self.lower_body(None, |this| this.lower_expr(expr));
hir::TyTypeof(expr)
}
- TyKind::TraitObject(ref bounds, ..) => {
+ TyKind::TraitObject(ref bounds, kind) => {
let mut lifetime_bound = None;
let bounds = bounds.iter().filter_map(|bound| {
match *bound {
let lifetime_bound = lifetime_bound.unwrap_or_else(|| {
self.elided_lifetime(t.span)
});
+ if kind != TraitObjectSyntax::Dyn {
+ self.maybe_lint_bare_trait(t.span, t.id, false);
+ }
hir::TyTraitObject(bounds, lifetime_bound)
}
TyKind::ImplTrait(ref bounds) => {
}
fn lower_pat(&mut self, p: &Pat) -> P<hir::Pat> {
- let LoweredNodeId { node_id, hir_id } = self.lower_node_id(p.id);
+ let node = match p.node {
+ PatKind::Wild => hir::PatKind::Wild,
+ PatKind::Ident(ref binding_mode, pth1, ref sub) => {
+ match self.resolver.get_resolution(p.id).map(|d| d.base_def()) {
+ // `None` can occur in body-less function signatures
+ def @ None | def @ Some(Def::Local(_)) => {
+ let canonical_id = match def {
+ Some(Def::Local(id)) => id,
+ _ => p.id
+ };
+ hir::PatKind::Binding(self.lower_binding_mode(binding_mode),
+ canonical_id,
+ respan(pth1.span, pth1.node.name),
+ sub.as_ref().map(|x| self.lower_pat(x)))
+ }
+ Some(def) => {
+ hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
+ span: pth1.span,
+ def,
+ segments: hir_vec![
+ hir::PathSegment::from_name(pth1.node.name)
+ ],
+ })))
+ }
+ }
+ }
+ PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
+ PatKind::TupleStruct(ref path, ref pats, ddpos) => {
+ let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
+ ImplTraitContext::Disallowed);
+ hir::PatKind::TupleStruct(qpath,
+ pats.iter().map(|x| self.lower_pat(x)).collect(),
+ ddpos)
+ }
+ PatKind::Path(ref qself, ref path) => {
+ hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional,
+ ImplTraitContext::Disallowed))
+ }
+ PatKind::Struct(ref path, ref fields, etc) => {
+ let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
+ ImplTraitContext::Disallowed);
+
+ let fs = fields.iter()
+ .map(|f| {
+ Spanned {
+ span: f.span,
+ node: hir::FieldPat {
+ name: self.lower_ident(f.node.ident),
+ pat: self.lower_pat(&f.node.pat),
+ is_shorthand: f.node.is_shorthand,
+ },
+ }
+ })
+ .collect();
+ hir::PatKind::Struct(qpath, fs, etc)
+ }
+ PatKind::Tuple(ref elts, ddpos) => {
+ hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
+ }
+ PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
+ PatKind::Ref(ref inner, mutbl) => {
+ hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
+ }
+ PatKind::Range(ref e1, ref e2, ref end) => {
+ hir::PatKind::Range(P(self.lower_expr(e1)),
+ P(self.lower_expr(e2)),
+ self.lower_range_end(end))
+ }
+ PatKind::Slice(ref before, ref slice, ref after) => {
+ hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
+ slice.as_ref().map(|x| self.lower_pat(x)),
+ after.iter().map(|x| self.lower_pat(x)).collect())
+ }
+ PatKind::Paren(ref inner) => return self.lower_pat(inner),
+ PatKind::Mac(_) => panic!("Shouldn't exist here"),
+ };
+ let LoweredNodeId { node_id, hir_id } = self.lower_node_id(p.id);
P(hir::Pat {
id: node_id,
hir_id,
- node: match p.node {
- PatKind::Wild => hir::PatKind::Wild,
- PatKind::Ident(ref binding_mode, pth1, ref sub) => {
- match self.resolver.get_resolution(p.id).map(|d| d.base_def()) {
- // `None` can occur in body-less function signatures
- def @ None | def @ Some(Def::Local(_)) => {
- let canonical_id = match def {
- Some(Def::Local(id)) => id,
- _ => p.id
- };
- hir::PatKind::Binding(self.lower_binding_mode(binding_mode),
- canonical_id,
- respan(pth1.span, pth1.node.name),
- sub.as_ref().map(|x| self.lower_pat(x)))
- }
- Some(def) => {
- hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
- span: pth1.span,
- def,
- segments: hir_vec![
- hir::PathSegment::from_name(pth1.node.name)
- ],
- })))
- }
- }
- }
- PatKind::Lit(ref e) => hir::PatKind::Lit(P(self.lower_expr(e))),
- PatKind::TupleStruct(ref path, ref pats, ddpos) => {
- let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
- ImplTraitContext::Disallowed);
- hir::PatKind::TupleStruct(qpath,
- pats.iter().map(|x| self.lower_pat(x)).collect(),
- ddpos)
- }
- PatKind::Path(ref qself, ref path) => {
- hir::PatKind::Path(self.lower_qpath(p.id, qself, path, ParamMode::Optional,
- ImplTraitContext::Disallowed))
- }
- PatKind::Struct(ref path, ref fields, etc) => {
- let qpath = self.lower_qpath(p.id, &None, path, ParamMode::Optional,
- ImplTraitContext::Disallowed);
-
- let fs = fields.iter()
- .map(|f| {
- Spanned {
- span: f.span,
- node: hir::FieldPat {
- name: self.lower_ident(f.node.ident),
- pat: self.lower_pat(&f.node.pat),
- is_shorthand: f.node.is_shorthand,
- },
- }
- })
- .collect();
- hir::PatKind::Struct(qpath, fs, etc)
- }
- PatKind::Tuple(ref elts, ddpos) => {
- hir::PatKind::Tuple(elts.iter().map(|x| self.lower_pat(x)).collect(), ddpos)
- }
- PatKind::Box(ref inner) => hir::PatKind::Box(self.lower_pat(inner)),
- PatKind::Ref(ref inner, mutbl) => {
- hir::PatKind::Ref(self.lower_pat(inner), self.lower_mutability(mutbl))
- }
- PatKind::Range(ref e1, ref e2, ref end) => {
- hir::PatKind::Range(P(self.lower_expr(e1)),
- P(self.lower_expr(e2)),
- self.lower_range_end(end))
- }
- PatKind::Slice(ref before, ref slice, ref after) => {
- hir::PatKind::Slice(before.iter().map(|x| self.lower_pat(x)).collect(),
- slice.as_ref().map(|x| self.lower_pat(x)),
- after.iter().map(|x| self.lower_pat(x)).collect())
- }
- PatKind::Mac(_) => panic!("Shouldn't exist here"),
- },
+ node,
span: p.span,
})
}
// The original ID is taken by the `PolyTraitRef`,
// so the `Ty` itself needs a different one.
id = self.next_id();
-
hir::TyTraitObject(hir_vec![principal], self.elided_lifetime(span))
} else {
hir::TyPath(hir::QPath::Resolved(None, path))
name: hir::LifetimeName::Implicit,
}
}
+
+ fn maybe_lint_bare_trait(&self, span: Span, id: NodeId, is_global: bool) {
+ if self.sess.features.borrow().dyn_trait {
+ self.sess.buffer_lint_with_diagnostic(
+ builtin::BARE_TRAIT_OBJECT, id, span,
+ "trait objects without an explicit `dyn` are deprecated",
+ builtin::BuiltinLintDiagnostics::BareTraitObject(span, is_global)
+ )
+ }
+ }
}
fn body_ids(bodies: &BTreeMap<hir::BodyId, hir::Body>) -> Vec<hir::BodyId> {
html_root_url = "https://doc.rust-lang.org/nightly/")]
#![deny(warnings)]
+#![cfg_attr(not(stage0), allow(bare_trait_object))]
+
#![feature(box_patterns)]
#![feature(box_syntax)]
#![feature(conservative_impl_trait)]
//! compiler code, rather than using their own custom pass. Those
//! lints are all available in `rustc_lint::builtin`.
+use errors::DiagnosticBuilder;
use lint::{LintPass, LateLintPass, LintArray};
+use session::Session;
+use session::config::Epoch;
+use syntax::codemap::Span;
declare_lint! {
pub CONST_ERR,
"hidden lifetime parameters are deprecated, try `Foo<'_>`"
}
+declare_lint! {
+ pub BARE_TRAIT_OBJECT,
+ Warn,
+ "suggest using `dyn Trait` for trait objects",
+ Epoch::Epoch2018
+}
+
/// Does nothing as a lint pass, but registers some `Lint`s
/// which are used by other parts of the compiler.
#[derive(Copy, Clone)]
COERCE_NEVER,
SINGLE_USE_LIFETIME,
TYVAR_BEHIND_RAW_POINTER,
- ELIDED_LIFETIME_IN_PATH
-
+ ELIDED_LIFETIME_IN_PATH,
+ BARE_TRAIT_OBJECT
)
}
}
+// this could be a closure, but then implementing derive traits
+// becomes hacky (and it gets allocated)
+#[derive(PartialEq, RustcEncodable, RustcDecodable, Debug)]
+pub enum BuiltinLintDiagnostics {
+ Normal,
+ BareTraitObject(Span, /* is_global */ bool)
+}
+
+impl BuiltinLintDiagnostics {
+ pub fn run(self, sess: &Session, db: &mut DiagnosticBuilder) {
+ match self {
+ BuiltinLintDiagnostics::Normal => (),
+ BuiltinLintDiagnostics::BareTraitObject(span, is_global) => {
+ let sugg = match sess.codemap().span_to_snippet(span) {
+ Ok(ref s) if is_global => format!("dyn ({})", s),
+ Ok(s) => format!("dyn {}", s),
+ Err(_) => format!("dyn <type>")
+ };
+ db.span_suggestion(span, "use `dyn`", sugg);
+ }
+ }
+ }
+}
+
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for HardwiredLints {}
use std::slice;
use lint::{EarlyLintPassObject, LateLintPassObject};
use lint::{Level, Lint, LintId, LintPass, LintBuffer};
+use lint::builtin::BuiltinLintDiagnostics;
use lint::levels::{LintLevelSets, LintLevelsBuilder};
use middle::privacy::AccessLevels;
use rustc_serialize::{Decoder, Decodable, Encoder, Encodable};
pub ast_id: ast::NodeId,
pub span: MultiSpan,
pub msg: String,
+ pub diagnostic: BuiltinLintDiagnostics,
}
/// Extra information for a future incompatibility lint. See the call
/// guidelines.
pub struct FutureIncompatibleInfo {
pub id: LintId,
- pub reference: &'static str // e.g., a URL for an issue/PR/RFC or error code
+ /// e.g., a URL for an issue/PR/RFC or error code
+ pub reference: &'static str,
+ /// If this is an epoch fixing lint, the epoch in which
+ /// this lint becomes obsolete
+ pub epoch: Option<config::Epoch>,
}
/// The target of the `by_name` map, which accounts for renaming/deprecation.
pub fn register_future_incompatible(&mut self,
sess: Option<&Session>,
lints: Vec<FutureIncompatibleInfo>) {
- let ids = lints.iter().map(|f| f.id).collect();
- self.register_group(sess, false, "future_incompatible", ids);
- for info in lints {
- self.future_incompatible.insert(info.id, info);
+
+ for epoch in config::ALL_EPOCHS {
+ let lints = lints.iter().filter(|f| f.epoch == Some(*epoch)).map(|f| f.id)
+ .collect::<Vec<_>>();
+ if !lints.is_empty() {
+ self.register_group(sess, false, epoch.lint_name(), lints)
+ }
}
+
+ let mut future_incompatible = vec![];
+ for lint in lints {
+ future_incompatible.push(lint.id);
+ self.future_incompatible.insert(lint.id, lint);
+ }
+
+ self.register_group(sess, false, "future_incompatible", future_incompatible);
+
+
}
pub fn future_incompatible(&self, id: LintId) -> Option<&FutureIncompatibleInfo> {
self.lookup(lint, span, msg).emit();
}
+ fn lookup_and_emit_with_diagnostics<S: Into<MultiSpan>>(&self,
+ lint: &'static Lint,
+ span: Option<S>,
+ msg: &str,
+ diagnostic: BuiltinLintDiagnostics) {
+ let mut db = self.lookup(lint, span, msg);
+ diagnostic.run(self.sess(), &mut db);
+ db.emit();
+ }
+
fn lookup<S: Into<MultiSpan>>(&self,
lint: &'static Lint,
span: Option<S>,
fn check_id(&mut self, id: ast::NodeId) {
for early_lint in self.buffered.take(id) {
- self.lookup_and_emit(early_lint.lint_id.lint,
- Some(early_lint.span.clone()),
- &early_lint.msg);
+ self.lookup_and_emit_with_diagnostics(early_lint.lint_id.lint,
+ Some(early_lint.span.clone()),
+ &early_lint.msg,
+ early_lint.diagnostic);
}
}
}
if !sess.opts.actually_rustdoc {
for (_id, lints) in cx.buffered.map {
for early_lint in lints {
- span_bug!(early_lint.span, "failed to process buffered lint here");
+ sess.delay_span_bug(early_lint.span, "failed to process buffered lint here");
}
}
}
fn get_lint_level(&self,
lint: &'static Lint,
idx: u32,
- aux: Option<&FxHashMap<LintId, (Level, LintSource)>>)
+ aux: Option<&FxHashMap<LintId, (Level, LintSource)>>,
+ sess: &Session)
-> (Level, LintSource)
{
let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux);
// If `level` is none then we actually assume the default level for this
// lint.
- let mut level = level.unwrap_or(lint.default_level);
+ let mut level = level.unwrap_or(lint.default_level(sess));
// If we're about to issue a warning, check at the last minute for any
// directives against the warnings "lint". If, for example, there's an
let lint = builtin::RENAMED_AND_REMOVED_LINTS;
let (level, src) = self.sets.get_lint_level(lint,
self.cur,
- Some(&specs));
+ Some(&specs),
+ &sess);
lint::struct_lint_level(self.sess,
lint,
level,
let lint = builtin::UNKNOWN_LINTS;
let (level, src) = self.sets.get_lint_level(lint,
self.cur,
- Some(&specs));
+ Some(&specs),
+ self.sess);
let msg = format!("unknown lint: `{}`", name);
let mut db = lint::struct_lint_level(self.sess,
lint,
msg: &str)
-> DiagnosticBuilder<'a>
{
- let (level, src) = self.sets.get_lint_level(lint, self.cur, None);
+ let (level, src) = self.sets.get_lint_level(lint, self.cur, None, self.sess);
lint::struct_lint_level(self.sess, lint, level, src, span, msg)
}
/// If the `id` was not previously registered, returns `None`. If `None` is
/// returned then the parent of `id` should be acquired and this function
/// should be called again.
- pub fn level_and_source(&self, lint: &'static Lint, id: HirId)
+ pub fn level_and_source(&self, lint: &'static Lint, id: HirId, session: &Session)
-> Option<(Level, LintSource)>
{
self.id_to_set.get(&id).map(|idx| {
- self.sets.get_lint_level(lint, *idx, None)
+ self.sets.get_lint_level(lint, *idx, None, session)
})
}
use hir::def_id::{CrateNum, LOCAL_CRATE};
use hir::intravisit::{self, FnKind};
use hir;
-use session::{Session, DiagnosticMessageId};
+use lint::builtin::BuiltinLintDiagnostics;
+use session::{config, Session, DiagnosticMessageId};
use std::hash;
use syntax::ast;
use syntax::codemap::MultiSpan;
///
/// e.g. "imports that are never used"
pub desc: &'static str,
+
+ /// Deny lint after this epoch
+ pub epoch_deny: Option<config::Epoch>,
}
impl Lint {
pub fn name_lower(&self) -> String {
self.name.to_ascii_lowercase()
}
+
+ pub fn default_level(&self, session: &Session) -> Level {
+ if let Some(epoch_deny) = self.epoch_deny {
+ if session.epoch() >= epoch_deny {
+ return Level::Deny
+ }
+ }
+ self.default_level
+ }
}
/// Declare a static item of type `&'static Lint`.
#[macro_export]
macro_rules! declare_lint {
+ ($vis: vis $NAME: ident, $Level: ident, $desc: expr, $epoch: expr) => (
+ $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
+ name: stringify!($NAME),
+ default_level: $crate::lint::$Level,
+ desc: $desc,
+ epoch_deny: Some($epoch)
+ };
+ );
($vis: vis $NAME: ident, $Level: ident, $desc: expr) => (
$vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint {
name: stringify!($NAME),
default_level: $crate::lint::$Level,
- desc: $desc
+ desc: $desc,
+ epoch_deny: None,
};
- )
+ );
}
/// Declare a static `LintArray` and return it as an expression.
/// Setting for how to handle a lint.
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
pub enum Level {
- Allow, Warn, Deny, Forbid
+ Allow, Warn, Deny, Forbid,
}
impl_stable_hash_for!(enum self::Level {
lint: &'static Lint,
id: ast::NodeId,
sp: MultiSpan,
- msg: &str) {
+ msg: &str,
+ diagnostic: BuiltinLintDiagnostics) {
let early_lint = BufferedEarlyLint {
lint_id: LintId::of(lint),
ast_id: id,
span: sp,
msg: msg.to_string(),
+ diagnostic
};
let arr = self.map.entry(id).or_insert(Vec::new());
if !arr.contains(&early_lint) {
use std::collections::btree_map::Keys as BTreeMapKeysIter;
use std::collections::btree_map::Values as BTreeMapValuesIter;
-use std::fmt;
+use std::{fmt, str};
use std::hash::Hasher;
use std::collections::hash_map::DefaultHasher;
use std::collections::HashSet;
}
/// The epoch of the compiler (RFC 2052)
-#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq)]
+#[derive(Clone, Copy, Hash, PartialOrd, Ord, Eq, PartialEq, Debug)]
#[non_exhaustive]
pub enum Epoch {
// epochs must be kept in order, newest to oldest
// as well as changing the default Cargo template.
}
+pub const ALL_EPOCHS: &[Epoch] = &[Epoch::Epoch2015, Epoch::Epoch2018];
+
+impl ToString for Epoch {
+ fn to_string(&self) -> String {
+ match *self {
+ Epoch::Epoch2015 => "2015".into(),
+ Epoch::Epoch2018 => "2018".into(),
+ }
+ }
+}
+
+impl Epoch {
+ pub fn lint_name(&self) -> &'static str {
+ match *self {
+ Epoch::Epoch2015 => "epoch_2015",
+ Epoch::Epoch2018 => "epoch_2018",
+ }
+ }
+}
+
+impl str::FromStr for Epoch {
+ type Err = ();
+ fn from_str(s: &str) -> Result<Self, ()> {
+ match s {
+ "2015" => Ok(Epoch::Epoch2015),
+ "2018" => Ok(Epoch::Epoch2018),
+ _ => Err(())
+ }
+ }
+}
+
impl_stable_hash_for!(enum self::OutputType {
Bitcode,
Assembly,
// if we otherwise use the defaults of rustc.
cli_forced_codegen_units: Option<usize> [UNTRACKED],
cli_forced_thinlto_off: bool [UNTRACKED],
+
+ // Remap source path prefixes in all output (messages, object files, debug, etc)
+ remap_path_prefix: Vec<(PathBuf, PathBuf)> [UNTRACKED],
}
);
actually_rustdoc: false,
cli_forced_codegen_units: None,
cli_forced_thinlto_off: false,
+ remap_path_prefix: Vec::new(),
}
}
}
pub fn file_path_mapping(&self) -> FilePathMapping {
- FilePathMapping::new(
- self.debugging_opts.remap_path_prefix_from.iter().zip(
- self.debugging_opts.remap_path_prefix_to.iter()
- ).map(|(src, dst)| (src.clone(), dst.clone())).collect()
- )
+ FilePathMapping::new(self.remap_path_prefix.clone())
}
/// True if there will be an output file generated
fn parse_epoch(slot: &mut Epoch, v: Option<&str>) -> bool {
match v {
- Some("2015") => *slot = Epoch::Epoch2015,
- Some("2018") => *slot = Epoch::Epoch2018,
- _ => return false,
+ Some(s) => {
+ let epoch = s.parse();
+ if let Ok(parsed) = epoch {
+ *slot = parsed;
+ true
+ } else {
+ false
+ }
+ }
+ _ => false,
}
- true
}
}
) }
"set the optimization fuel quota for a crate"),
print_fuel: Option<String> = (None, parse_opt_string, [TRACKED],
"make Rustc print the total optimization fuel used by a crate"),
- remap_path_prefix_from: Vec<PathBuf> = (vec![], parse_pathbuf_push, [UNTRACKED],
- "add a source pattern to the file path remapping config"),
- remap_path_prefix_to: Vec<PathBuf> = (vec![], parse_pathbuf_push, [UNTRACKED],
- "add a mapping target to the file path remapping config"),
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
"force all crates to be `rustc_private` unstable"),
pre_link_arg: Vec<String> = (vec![], parse_string_push, [UNTRACKED],
`expanded` (crates expanded), or
`expanded,identified` (fully parenthesized, AST nodes with IDs).",
"TYPE"),
+ opt::multi_s("", "remap-path-prefix", "remap source names in output", "FROM=TO"),
]);
opts
}
output_types.insert(OutputType::Exe, None);
}
- let remap_path_prefix_sources = debugging_opts.remap_path_prefix_from.len();
- let remap_path_prefix_targets = debugging_opts.remap_path_prefix_to.len();
-
- if remap_path_prefix_targets < remap_path_prefix_sources {
- for source in &debugging_opts.remap_path_prefix_from[remap_path_prefix_targets..] {
- early_error(error_format,
- &format!("option `-Zremap-path-prefix-from='{}'` does not have \
- a corresponding `-Zremap-path-prefix-to`", source.display()))
- }
- } else if remap_path_prefix_targets > remap_path_prefix_sources {
- for target in &debugging_opts.remap_path_prefix_to[remap_path_prefix_sources..] {
- early_error(error_format,
- &format!("option `-Zremap-path-prefix-to='{}'` does not have \
- a corresponding `-Zremap-path-prefix-from`", target.display()))
- }
- }
-
let mut cg = build_codegen_options(matches, error_format);
let mut codegen_units = cg.codegen_units;
let mut disable_thinlto = false;
let crate_name = matches.opt_str("crate-name");
+ let remap_path_prefix = matches.opt_strs("remap-path-prefix")
+ .into_iter()
+ .map(|remap| {
+ let mut parts = remap.rsplitn(2, '='); // reverse iterator
+ let to = parts.next();
+ let from = parts.next();
+ match (from, to) {
+ (Some(from), Some(to)) => (PathBuf::from(from), PathBuf::from(to)),
+ _ => early_error(error_format,
+ "--remap-path-prefix must contain '=' between FROM and TO"),
+ }
+ })
+ .collect();
+
(Options {
crate_types,
optimize: opt_level,
actually_rustdoc: false,
cli_forced_codegen_units: codegen_units,
cli_forced_thinlto_off: disable_thinlto,
+ remap_path_prefix,
},
cfg)
}
use ich;
use lint;
+use lint::builtin::BuiltinLintDiagnostics;
use middle::allocator::AllocatorKind;
use middle::dependency_format;
use session::search_paths::PathKind;
sp: S,
msg: &str) {
match *self.buffered_lints.borrow_mut() {
- Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(), msg),
+ Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(),
+ msg, BuiltinLintDiagnostics::Normal),
+ None => bug!("can't buffer lints after HIR lowering"),
+ }
+ }
+
+ pub fn buffer_lint_with_diagnostic<S: Into<MultiSpan>>(&self,
+ lint: &'static lint::Lint, id: ast::NodeId, sp: S,
+ msg: &str, diagnostic: BuiltinLintDiagnostics) {
+ match *self.buffered_lints.borrow_mut() {
+ Some(ref mut buffer) => buffer.add_lint(lint, id, sp.into(),
+ msg, diagnostic),
None => bug!("can't buffer lints after HIR lowering"),
}
}
pub fn rust_2018(&self) -> bool {
self.opts.debugging_opts.epoch >= Epoch::Epoch2018
}
+
+ pub fn epoch(&self) -> Epoch {
+ self.opts.debugging_opts.epoch
+ }
}
pub fn build_session(sopts: config::Options,
let sets = self.lint_levels(LOCAL_CRATE);
loop {
let hir_id = self.hir.definitions().node_to_hir_id(id);
- if let Some(pair) = sets.level_and_source(lint, hir_id) {
+ if let Some(pair) = sets.level_and_source(lint, hir_id, self.sess) {
return pair
}
let next = self.hir.get_parent_node(id);
// Lint plugins are registered; now we can process command line flags.
if sess.opts.describe_lints {
- super::describe_lints(&sess.lint_store.borrow(), true);
+ super::describe_lints(&sess, &sess.lint_store.borrow(), true);
return Err(CompileIncomplete::Stopped);
}
-> Option<(Input, Option<PathBuf>)> {
match matches.free.len() {
0 => {
+ let mut sess = build_session(sopts.clone(),
+ None,
+ descriptions.clone());
if sopts.describe_lints {
let mut ls = lint::LintStore::new();
- rustc_lint::register_builtins(&mut ls, None);
- describe_lints(&ls, false);
+ rustc_lint::register_builtins(&mut ls, Some(&sess));
+ describe_lints(&sess, &ls, false);
return None;
}
- let mut sess = build_session(sopts.clone(),
- None,
- descriptions.clone());
rustc_lint::register_builtins(&mut sess.lint_store.borrow_mut(), Some(&sess));
let mut cfg = config::build_configuration(&sess, cfg.clone());
let trans = get_trans(&sess);
verbose_help);
}
-fn describe_lints(lint_store: &lint::LintStore, loaded_plugins: bool) {
+fn describe_lints(sess: &Session, lint_store: &lint::LintStore, loaded_plugins: bool) {
println!("
Available lint options:
-W <foo> Warn about <foo>
");
- fn sort_lints(lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
+ fn sort_lints(sess: &Session, lints: Vec<(&'static Lint, bool)>) -> Vec<&'static Lint> {
let mut lints: Vec<_> = lints.into_iter().map(|(x, _)| x).collect();
lints.sort_by(|x: &&Lint, y: &&Lint| {
- match x.default_level.cmp(&y.default_level) {
+ match x.default_level(sess).cmp(&y.default_level(sess)) {
// The sort doesn't case-fold but it's doubtful we care.
Equal => x.name.cmp(y.name),
r => r,
.iter()
.cloned()
.partition(|&(_, p)| p);
- let plugin = sort_lints(plugin);
- let builtin = sort_lints(builtin);
+ let plugin = sort_lints(sess, plugin);
+ let builtin = sort_lints(sess, builtin);
let (plugin_groups, builtin_groups): (Vec<_>, _) = lint_store.get_lint_groups()
.iter()
PatKind::TupleStruct(..) |
PatKind::Ref(..) |
PatKind::Box(..) |
+ PatKind::Paren(..) |
PatKind::Slice(..) => (),
// Extract the expressions and check them
FutureIncompatibleInfo {
id: LintId::of(PRIVATE_IN_PUBLIC),
reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(PUB_USE_OF_PRIVATE_EXTERN_CRATE),
reference: "issue #34537 <https://github.com/rust-lang/rust/issues/34537>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(PATTERNS_IN_FNS_WITHOUT_BODY),
reference: "issue #35203 <https://github.com/rust-lang/rust/issues/35203>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(SAFE_EXTERN_STATICS),
reference: "issue #36247 <https://github.com/rust-lang/rust/issues/36247>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(INVALID_TYPE_PARAM_DEFAULT),
reference: "issue #36887 <https://github.com/rust-lang/rust/issues/36887>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(LEGACY_DIRECTORY_OWNERSHIP),
reference: "issue #37872 <https://github.com/rust-lang/rust/issues/37872>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(LEGACY_IMPORTS),
reference: "issue #38260 <https://github.com/rust-lang/rust/issues/38260>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(LEGACY_CONSTRUCTOR_VISIBILITY),
reference: "issue #39207 <https://github.com/rust-lang/rust/issues/39207>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(RESOLVE_TRAIT_ON_DEFAULTED_UNIT),
reference: "issue #39216 <https://github.com/rust-lang/rust/issues/39216>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(MISSING_FRAGMENT_SPECIFIER),
reference: "issue #40107 <https://github.com/rust-lang/rust/issues/40107>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(ILLEGAL_FLOATING_POINT_LITERAL_PATTERN),
reference: "issue #41620 <https://github.com/rust-lang/rust/issues/41620>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(ANONYMOUS_PARAMETERS),
reference: "issue #41686 <https://github.com/rust-lang/rust/issues/41686>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(PARENTHESIZED_PARAMS_IN_TYPES_AND_MODULES),
reference: "issue #42238 <https://github.com/rust-lang/rust/issues/42238>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(LATE_BOUND_LIFETIME_ARGUMENTS),
reference: "issue #42868 <https://github.com/rust-lang/rust/issues/42868>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(SAFE_PACKED_BORROWS),
reference: "issue #46043 <https://github.com/rust-lang/rust/issues/46043>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(INCOHERENT_FUNDAMENTAL_IMPLS),
reference: "issue #46205 <https://github.com/rust-lang/rust/issues/46205>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(COERCE_NEVER),
reference: "issue #46325 <https://github.com/rust-lang/rust/issues/46325>",
+ epoch: None,
},
FutureIncompatibleInfo {
id: LintId::of(TYVAR_BEHIND_RAW_POINTER),
reference: "issue #46906 <https://github.com/rust-lang/rust/issues/46906>",
+ epoch: None,
},
+ FutureIncompatibleInfo {
+ id: LintId::of(lint::builtin::BARE_TRAIT_OBJECT),
+ reference: "issue #48457 <https://github.com/rust-lang/rust/issues/48457>",
+ epoch: Some(session::config::Epoch::Epoch2018),
+ }
]);
// Register renamed and removed lints
// paths because any relative paths are potentially relative to
// a wrong directory.
// However, if a path has been modified via
- // `-Zremap-path-prefix` we assume the user has already set
+ // `--remap-path-prefix` we assume the user has already set
// things up the way they want and don't touch the path values
// anymore.
match filemap.name {
use std::u32;
use syntax::abi::Abi;
use syntax::ast;
+use syntax::attr::{self, UnwindAttr};
use syntax::symbol::keywords;
use syntax_pos::Span;
use transform::MirSource;
}
fn should_abort_on_panic<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- fn_id: ast::NodeId,
+ fn_def_id: DefId,
abi: Abi)
-> bool {
-
// Not callable from C, so we can safely unwind through these
if abi == Abi::Rust || abi == Abi::RustCall { return false; }
// This is a special case: some functions have a C abi but are meant to
// unwind anyway. Don't stop them.
- if tcx.has_attr(tcx.hir.local_def_id(fn_id), "unwind") { return false; }
+ let attrs = &tcx.get_attrs(fn_def_id);
+ match attr::find_unwind_attr(Some(tcx.sess.diagnostic()), attrs) {
+ None => {
+ // FIXME(rust-lang/rust#48251) -- Had to disable
+ // abort-on-panic for backwards compatibility reasons.
+ false
+ }
- return true;
+ Some(UnwindAttr::Allowed) => false,
+ Some(UnwindAttr::Aborts) => true,
+ }
}
///////////////////////////////////////////////////////////////////////////
safety,
return_ty);
+ let fn_def_id = tcx.hir.local_def_id(fn_id);
let call_site_scope = region::Scope::CallSite(body.value.hir_id.local_id);
let arg_scope = region::Scope::Arguments(body.value.hir_id.local_id);
let mut block = START_BLOCK;
let source_info = builder.source_info(span);
let call_site_s = (call_site_scope, source_info);
unpack!(block = builder.in_scope(call_site_s, LintLevel::Inherited, block, |builder| {
- if should_abort_on_panic(tcx, fn_id, abi) {
+ if should_abort_on_panic(tcx, fn_def_id, abi) {
builder.schedule_abort();
}
*/
#![deny(warnings)]
+#![cfg_attr(not(stage0), allow(bare_trait_object))]
#![feature(box_patterns)]
#![feature(box_syntax)]
// Optimizations begin.
+ uniform_array_move_out::RestoreSubsliceArrayMoveOut,
inline::Inline,
// Lowering generator control-flow and variables
// and mir statement _11 = move _2[-1 of 1]; replaced by:
// _11 = move _2[2 of 3];
//
-// FIXME: convert to Subslice back for performance reason
// FIXME: integrate this transformation to the mir build
use rustc::ty;
use rustc::ty::TyCtxt;
use rustc::mir::*;
-use rustc::mir::visit::Visitor;
+use rustc::mir::visit::{Visitor, PlaceContext};
use transform::{MirPass, MirSource};
use util::patch::MirPatch;
+use rustc_data_structures::indexed_vec::{IndexVec};
pub struct UniformArrayMoveOut;
}
impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
- fn visit_statement(&mut self,
- block: BasicBlock,
- statement: &Statement<'tcx>,
- location: Location) {
- if let StatementKind::Assign(ref dst_place,
- Rvalue::Use(Operand::Move(ref src_place))) = statement.kind {
+ fn visit_assign(&mut self,
+ block: BasicBlock,
+ dst_place: &Place<'tcx>,
+ rvalue: &Rvalue<'tcx>,
+ location: Location) {
+ if let Rvalue::Use(Operand::Move(ref src_place)) = rvalue {
if let Place::Projection(ref proj) = *src_place {
if let ProjectionElem::ConstantIndex{offset: _,
min_length: _,
}
}
}
- return self.super_statement(block, statement, location);
+ self.super_assign(block, dst_place, rvalue, location)
}
}
item_ty: &'tcx ty::TyS<'tcx>,
size: u32) {
match proj.elem {
- // uniform _10 = move _2[:-1];
+ // uniforms statements like_10 = move _2[:-1];
ProjectionElem::Subslice{from, to} => {
self.patch.make_nop(location);
let temps : Vec<_> = (from..(size-to)).map(|i| {
self.patch.add_statement(location, StatementKind::StorageDead(temp));
}
}
- // _11 = move _2[-1 of 1];
+ // uniforms statements like _11 = move _2[-1 of 1];
ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true} => {
self.patch.make_nop(location);
self.patch.add_assign(location,
}
}
}
+
+// Restore Subslice move out after analysis
+// Example:
+//
+// next statements:
+// StorageLive(_12);
+// _12 = move _2[0 of 3];
+// StorageLive(_13);
+// _13 = move _2[1 of 3];
+// _10 = [move _12, move _13]
+// StorageDead(_12);
+// StorageDead(_13);
+//
+// replaced by _10 = move _2[:-1];
+
+pub struct RestoreSubsliceArrayMoveOut;
+
+impl MirPass for RestoreSubsliceArrayMoveOut {
+ fn run_pass<'a, 'tcx>(&self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ _src: MirSource,
+ mir: &mut Mir<'tcx>) {
+ let mut patch = MirPatch::new(mir);
+ {
+ let mut visitor = RestoreDataCollector {
+ locals_use: IndexVec::from_elem(LocalUse::new(), &mir.local_decls),
+ candidates: vec![],
+ };
+ visitor.visit_mir(mir);
+
+ for candidate in &visitor.candidates {
+ let statement = &mir[candidate.block].statements[candidate.statement_index];
+ if let StatementKind::Assign(ref dst_place, ref rval) = statement.kind {
+ if let Rvalue::Aggregate(box AggregateKind::Array(_), ref items) = *rval {
+ let items : Vec<_> = items.iter().map(|item| {
+ if let Operand::Move(Place::Local(local)) = item {
+ let local_use = &visitor.locals_use[*local];
+ let opt_index_and_place = Self::try_get_item_source(local_use, mir);
+ // each local should be used twice:
+ // in assign and in aggregate statments
+ if local_use.use_count == 2 && opt_index_and_place.is_some() {
+ let (index, src_place) = opt_index_and_place.unwrap();
+ return Some((local_use, index, src_place));
+ }
+ }
+ None
+ }).collect();
+
+ let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
+ let opt_size = opt_src_place.and_then(|src_place| {
+ let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
+ if let ty::TyArray(_, ref size_o) = src_ty.sty {
+ size_o.val.to_const_int().and_then(|v| v.to_u64())
+ } else {
+ None
+ }
+ });
+ Self::check_and_patch(*candidate, &items, opt_size, &mut patch, dst_place);
+ }
+ }
+ }
+ }
+ patch.apply(mir);
+ }
+}
+
+impl RestoreSubsliceArrayMoveOut {
+ // Checks that source has size, all locals are inited from same source place and
+ // indices is an integer interval. If all checks pass do the replacent.
+ // items are Vec<Option<LocalUse, index in source array, source place for init local>>
+ fn check_and_patch<'tcx>(candidate: Location,
+ items: &Vec<Option<(&LocalUse, u32, &Place<'tcx>)>>,
+ opt_size: Option<u64>,
+ patch: &mut MirPatch<'tcx>,
+ dst_place: &Place<'tcx>) {
+ let opt_src_place = items.first().and_then(|x| *x).map(|x| x.2);
+
+ if opt_size.is_some() && items.iter().all(
+ |l| l.is_some() && l.unwrap().2 == opt_src_place.unwrap()) {
+
+ let indicies: Vec<_> = items.iter().map(|x| x.unwrap().1).collect();
+ for i in 1..indicies.len() {
+ if indicies[i - 1] + 1 != indicies[i] {
+ return;
+ }
+ }
+
+ let min = *indicies.first().unwrap();
+ let max = *indicies.last().unwrap();
+
+ for item in items {
+ let locals_use = item.unwrap().0;
+ patch.make_nop(locals_use.alive.unwrap());
+ patch.make_nop(locals_use.dead.unwrap());
+ patch.make_nop(locals_use.first_use.unwrap());
+ }
+ patch.make_nop(candidate);
+ let size = opt_size.unwrap() as u32;
+ patch.add_assign(candidate,
+ dst_place.clone(),
+ Rvalue::Use(
+ Operand::Move(
+ Place::Projection(box PlaceProjection{
+ base: opt_src_place.unwrap().clone(),
+ elem: ProjectionElem::Subslice{
+ from: min, to: size - max - 1}}))));
+ }
+ }
+
+ fn try_get_item_source<'a, 'tcx>(local_use: &LocalUse,
+ mir: &'a Mir<'tcx>) -> Option<(u32, &'a Place<'tcx>)> {
+ if let Some(location) = local_use.first_use {
+ let block = &mir[location.block];
+ if block.statements.len() > location.statement_index {
+ let statement = &block.statements[location.statement_index];
+ if let StatementKind::Assign(
+ Place::Local(_),
+ Rvalue::Use(Operand::Move(Place::Projection(box PlaceProjection{
+ ref base, elem: ProjectionElem::ConstantIndex{
+ offset, min_length: _, from_end: false}})))) = statement.kind {
+ return Some((offset, base))
+ }
+ }
+ }
+ None
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+struct LocalUse {
+ alive: Option<Location>,
+ dead: Option<Location>,
+ use_count: u32,
+ first_use: Option<Location>,
+}
+
+impl LocalUse {
+ pub fn new() -> Self {
+ LocalUse{alive: None, dead: None, use_count: 0, first_use: None}
+ }
+}
+
+struct RestoreDataCollector {
+ locals_use: IndexVec<Local, LocalUse>,
+ candidates: Vec<Location>,
+}
+
+impl<'tcx> Visitor<'tcx> for RestoreDataCollector {
+ fn visit_assign(&mut self,
+ block: BasicBlock,
+ place: &Place<'tcx>,
+ rvalue: &Rvalue<'tcx>,
+ location: Location) {
+ if let Rvalue::Aggregate(box AggregateKind::Array(_), _) = *rvalue {
+ self.candidates.push(location);
+ }
+ self.super_assign(block, place, rvalue, location)
+ }
+
+ fn visit_local(&mut self,
+ local: &Local,
+ context: PlaceContext<'tcx>,
+ location: Location) {
+ let local_use = &mut self.locals_use[*local];
+ match context {
+ PlaceContext::StorageLive => local_use.alive = Some(location),
+ PlaceContext::StorageDead => local_use.dead = Some(location),
+ _ => {
+ local_use.use_count += 1;
+ if local_use.first_use.is_none() {
+ local_use.first_use = Some(location);
+ }
+ }
+ }
+ }
+}
// parameter in this type parameter list
```
-Please verify that none of the type parameterss are misspelled, and rename any
+Please verify that none of the type parameters are misspelled, and rename any
clashing parameters. Example:
```
"##,
E0404: r##"
-You tried to implement something which was not a trait on an object.
+You tried to use something which is not a trait in a trait position, such as
+a bound or `impl`.
Erroneous code example:
impl Foo for Bar {} // error: `Foo` is not a trait
```
+Another erroneous code example:
+
+```compile_fail,E0404
+struct Foo;
+
+fn bar<T: Foo>(t: T) {} // error: `Foo` is not a trait
+```
+
Please verify that you didn't misspell the trait's name or otherwise use the
wrong identifier. Example:
// functions implementation
}
```
+
+or
+
+```
+trait Foo {
+ // some functions
+}
+
+fn bar<T: Foo>(t: T) {} // ok!
+```
+
"##,
E0405: r##"
result
}
+ /// This is called to resolve a trait reference from an `impl` (i.e. `impl Trait for Foo`)
fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
where F: FnOnce(&mut Resolver, Option<DefId>) -> T
{
let path: Vec<_> = trait_ref.path.segments.iter()
.map(|seg| respan(seg.span, seg.identifier))
.collect();
- let def = self.smart_resolve_path_fragment(trait_ref.ref_id,
- None,
- &path,
- trait_ref.path.span,
- trait_ref.path.segments.last().unwrap().span,
- PathSource::Trait(AliasPossibility::No))
- .base_def();
+ let def = self.smart_resolve_path_fragment(
+ trait_ref.ref_id,
+ None,
+ &path,
+ trait_ref.path.span,
+ trait_ref.path.segments.last().unwrap().span,
+ PathSource::Trait(AliasPossibility::No)
+ ).base_def();
if def != Def::Err {
new_id = Some(def.def_id());
let span = trait_ref.path.span;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use common::{C_i32, C_null};
use libc::c_uint;
use llvm::{self, ValueRef, BasicBlockRef};
use llvm::debuginfo::DIScope;
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
use monomorphize::Instance;
use abi::{ArgAttribute, FnType, PassMode};
+use type_::Type;
use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
use syntax::symbol::keywords;
// Compute debuginfo scopes from MIR scopes.
let scopes = debuginfo::create_mir_scopes(cx, mir, &debug_context);
- let (landing_pads, funclets) = create_funclets(&bx, &cleanup_kinds, &block_bxs);
+ let (landing_pads, funclets) = create_funclets(mir, &bx, &cleanup_kinds, &block_bxs);
let mut fx = FunctionCx {
mir,
}
fn create_funclets<'a, 'tcx>(
+ mir: &'a Mir<'tcx>,
bx: &Builder<'a, 'tcx>,
cleanup_kinds: &IndexVec<mir::BasicBlock, CleanupKind>,
block_bxs: &IndexVec<mir::BasicBlock, BasicBlockRef>)
{
block_bxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| {
match *cleanup_kind {
- CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {
+ CleanupKind::Funclet if base::wants_msvc_seh(bx.sess()) => {}
+ _ => return (None, None)
+ }
+
+ let cleanup;
+ let ret_llbb;
+ match mir[bb].terminator.as_ref().map(|t| &t.kind) {
+ // This is a basic block that we're aborting the program for,
+ // notably in an `extern` function. These basic blocks are inserted
+ // so that we assert that `extern` functions do indeed not panic,
+ // and if they do we abort the process.
+ //
+ // On MSVC these are tricky though (where we're doing funclets). If
+ // we were to do a cleanuppad (like below) the normal functions like
+ // `longjmp` would trigger the abort logic, terminating the
+ // program. Instead we insert the equivalent of `catch(...)` for C++
+ // which magically doesn't trigger when `longjmp` files over this
+ // frame.
+ //
+ // Lots more discussion can be found on #48251 but this codegen is
+ // modeled after clang's for:
+ //
+ // try {
+ // foo();
+ // } catch (...) {
+ // bar();
+ // }
+ Some(&mir::TerminatorKind::Abort) => {
+ let cs_bx = bx.build_sibling_block(&format!("cs_funclet{:?}", bb));
+ let cp_bx = bx.build_sibling_block(&format!("cp_funclet{:?}", bb));
+ ret_llbb = cs_bx.llbb();
+
+ let cs = cs_bx.catch_switch(None, None, 1);
+ cs_bx.add_handler(cs, cp_bx.llbb());
+
+ // The "null" here is actually a RTTI type descriptor for the
+ // C++ personality function, but `catch (...)` has no type so
+ // it's null. The 64 here is actually a bitfield which
+ // represents that this is a catch-all block.
+ let null = C_null(Type::i8p(bx.cx));
+ let sixty_four = C_i32(bx.cx, 64);
+ cleanup = cp_bx.catch_pad(cs, &[null, sixty_four, null]);
+ cp_bx.br(llbb);
+ }
+ _ => {
let cleanup_bx = bx.build_sibling_block(&format!("funclet_{:?}", bb));
- let cleanup = cleanup_bx.cleanup_pad(None, &[]);
+ ret_llbb = cleanup_bx.llbb();
+ cleanup = cleanup_bx.cleanup_pad(None, &[]);
cleanup_bx.br(llbb);
- (Some(cleanup_bx.llbb()), Some(Funclet::new(cleanup)))
}
- _ => (None, None)
- }
+ };
+
+ (Some(ret_llbb), Some(Funclet::new(cleanup)))
}).unzip()
}
/// Instantiates the path for the given trait reference, assuming that it's
/// bound to a valid trait type. Returns the def_id for the defining trait.
- /// Fails if the type is a type other than a trait type.
+ /// The type _cannot_ be a type other than a trait type.
///
/// If the `projections` argument is `None`, then assoc type bindings like `Foo<T=X>`
/// are disallowed. Otherwise, they are pushed onto the vector given.
trait_ref.path.segments.last().unwrap())
}
+ /// Get the DefId of the given trait ref. It _must_ actually be a trait.
fn trait_def_id(&self, trait_ref: &hir::TraitRef) -> DefId {
let path = &trait_ref.path;
match path.def {
Def::Err => {
self.tcx().sess.fatal("cannot continue compilation due to previous error");
}
- _ => {
- span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait",
- self.tcx().hir.node_to_pretty_string(trait_ref.ref_id));
- }
+ _ => unreachable!(),
}
}
+ /// The given `trait_ref` must actually be trait.
pub(super) fn instantiate_poly_trait_ref_inner(&self,
trait_ref: &hir::TraitRef,
self_ty: Ty<'tcx>,
reject_shadowing_type_parameters(fcx.tcx, item.def_id);
let sig = fcx.tcx.fn_sig(item.def_id);
let sig = fcx.normalize_associated_types_in(span, &sig);
- let predicates = fcx.tcx.predicates_of(item.def_id)
- .instantiate_identity(fcx.tcx);
- let predicates = fcx.normalize_associated_types_in(span, &predicates);
- this.check_fn_or_method(fcx, span, sig, &predicates,
+ this.check_fn_or_method(fcx, span, sig,
item.def_id, &mut implied_bounds);
let sig_if_method = sig_if_method.expect("bad signature for method");
this.check_method_receiver(fcx, sig_if_method, &item, self_ty);
}
}
- let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
- let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
- this.check_where_clauses(fcx, item.span, &predicates);
+ self.check_where_clauses(fcx, item.span, def_id);
vec![] // no implied bounds in a struct def'n
});
fn check_trait(&mut self, item: &hir::Item) {
let trait_def_id = self.tcx.hir.local_def_id(item.id);
- self.for_item(item).with_fcx(|fcx, this| {
- let predicates = fcx.tcx.predicates_of(trait_def_id).instantiate_identity(fcx.tcx);
- let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
- this.check_where_clauses(fcx, item.span, &predicates);
+ self.for_item(item).with_fcx(|fcx, _| {
+ self.check_where_clauses(fcx, item.span, trait_def_id);
vec![]
});
}
let def_id = fcx.tcx.hir.local_def_id(item.id);
let sig = fcx.tcx.fn_sig(def_id);
let sig = fcx.normalize_associated_types_in(item.span, &sig);
-
- let predicates = fcx.tcx.predicates_of(def_id).instantiate_identity(fcx.tcx);
- let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
-
let mut implied_bounds = vec![];
- this.check_fn_or_method(fcx, item.span, sig, &predicates,
+ this.check_fn_or_method(fcx, item.span, sig,
def_id, &mut implied_bounds);
implied_bounds
})
}
}
- let predicates = fcx.tcx.predicates_of(item_def_id).instantiate_identity(fcx.tcx);
- let predicates = fcx.normalize_associated_types_in(item.span, &predicates);
- this.check_where_clauses(fcx, item.span, &predicates);
+ this.check_where_clauses(fcx, item.span, item_def_id);
fcx.impl_implied_bounds(item_def_id, item.span)
});
}
+ /// Checks where clauses and inline bounds that are declared on def_id.
fn check_where_clauses<'fcx, 'tcx>(&mut self,
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
span: Span,
- predicates: &ty::InstantiatedPredicates<'tcx>)
- {
+ def_id: DefId) {
+ use ty::subst::Subst;
+ use rustc::ty::TypeFoldable;
+
+ let mut predicates = fcx.tcx.predicates_of(def_id);
+ let mut substituted_predicates = Vec::new();
+
+ let generics = self.tcx.generics_of(def_id);
+ let is_our_default = |def: &ty::TypeParameterDef|
+ def.has_default && def.index >= generics.parent_count() as u32;
+
+ // Check that concrete defaults are well-formed. See test `type-check-defaults.rs`.
+ // For example this forbids the declaration:
+ // struct Foo<T = Vec<[u32]>> { .. }
+ // Here the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
+ for d in generics.types.iter().cloned().filter(is_our_default).map(|p| p.def_id) {
+ let ty = fcx.tcx.type_of(d);
+ // ignore dependent defaults -- that is, where the default of one type
+ // parameter includes another (e.g., <T, U = T>). In those cases, we can't
+ // be sure if it will error or not as user might always specify the other.
+ if !ty.needs_subst() {
+ fcx.register_wf_obligation(ty, fcx.tcx.def_span(d), self.code.clone());
+ }
+ }
+
+ // Check that trait predicates are WF when params are substituted by their defaults.
+ // We don't want to overly constrain the predicates that may be written but we want to
+ // catch cases where a default my never be applied such as `struct Foo<T: Copy = String>`.
+ // Therefore we check if a predicate which contains a single type param
+ // with a concrete default is WF with that default substituted.
+ // For more examples see tests `defaults-well-formedness.rs` and `type-check-defaults.rs`.
+ //
+ // First we build the defaulted substitution.
+ let substs = ty::subst::Substs::for_item(fcx.tcx, def_id, |def, _| {
+ // All regions are identity.
+ fcx.tcx.mk_region(ty::ReEarlyBound(def.to_early_bound_region_data()))
+ }, |def, _| {
+ // If the param has a default,
+ if is_our_default(def) {
+ let default_ty = fcx.tcx.type_of(def.def_id);
+ // and it's not a dependent default
+ if !default_ty.needs_subst() {
+ // then substitute with the default.
+ return default_ty;
+ }
+ }
+ // Mark unwanted params as err.
+ fcx.tcx.types.err
+ });
+ // Now we build the substituted predicates.
+ for &pred in predicates.predicates.iter() {
+ struct CountParams { params: FxHashSet<u32> }
+ impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams {
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+ match t.sty {
+ ty::TyParam(p) => {
+ self.params.insert(p.idx);
+ t.super_visit_with(self)
+ }
+ _ => t.super_visit_with(self)
+ }
+ }
+ }
+ let mut param_count = CountParams { params: FxHashSet() };
+ pred.visit_with(&mut param_count);
+ let substituted_pred = pred.subst(fcx.tcx, substs);
+ // Don't check non-defaulted params, dependent defaults or preds with multiple params.
+ if substituted_pred.references_error() || param_count.params.len() > 1 {
+ continue;
+ }
+ // Avoid duplication of predicates that contain no parameters, for example.
+ if !predicates.predicates.contains(&substituted_pred) {
+ substituted_predicates.push(substituted_pred);
+ }
+ }
+
+ predicates.predicates.extend(substituted_predicates);
+ let predicates = predicates.instantiate_identity(fcx.tcx);
+ let predicates = fcx.normalize_associated_types_in(span, &predicates);
+
let obligations =
predicates.predicates
.iter()
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
span: Span,
sig: ty::PolyFnSig<'tcx>,
- predicates: &ty::InstantiatedPredicates<'tcx>,
def_id: DefId,
implied_bounds: &mut Vec<Ty<'tcx>>)
{
// FIXME(#25759) return types should not be implied bounds
implied_bounds.push(sig.output());
- self.check_where_clauses(fcx, span, predicates);
+ self.check_where_clauses(fcx, span, def_id);
}
fn check_method_receiver<'fcx, 'tcx>(&mut self,
// E0240,
// E0241,
// E0242,
- E0245, // not a trait
+// E0245, // not a trait
// E0246, // invalid recursive type
// E0247,
// E0248, // value used as a type, now reported earlier during resolution as E0412
use sync::{Arc, Mutex, MutexGuard};
use sys::stdio;
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
-use thread::{LocalKey, LocalKeyState};
+use thread::LocalKey;
/// Stdout used by print! and println! macros
thread_local! {
///
/// This function is used to print error messages, so it takes extra
/// care to avoid causing a panic when `local_stream` is unusable.
-/// For instance, if the TLS key for the local stream is uninitialized
-/// or already destroyed, or if the local stream is locked by another
+/// For instance, if the TLS key for the local stream is
+/// already destroyed, or if the local stream is locked by another
/// thread, it will just fall back to the global stream.
///
/// However, if the actual I/O causes an error, this function does panic.
-fn print_to<T>(args: fmt::Arguments,
- local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
- global_s: fn() -> T,
- label: &str) where T: Write {
- let result = match local_s.state() {
- LocalKeyState::Uninitialized |
- LocalKeyState::Destroyed => global_s().write_fmt(args),
- LocalKeyState::Valid => {
- local_s.with(|s| {
- if let Ok(mut borrowed) = s.try_borrow_mut() {
- if let Some(w) = borrowed.as_mut() {
- return w.write_fmt(args);
- }
- }
- global_s().write_fmt(args)
- })
+fn print_to<T>(
+ args: fmt::Arguments,
+ local_s: &'static LocalKey<RefCell<Option<Box<Write+Send>>>>,
+ global_s: fn() -> T,
+ label: &str,
+)
+where
+ T: Write,
+{
+ let result = local_s.try_with(|s| {
+ if let Ok(mut borrowed) = s.try_borrow_mut() {
+ if let Some(w) = borrowed.as_mut() {
+ return w.write_fmt(args);
+ }
}
- };
+ global_s().write_fmt(args)
+ }).unwrap_or_else(|_| {
+ global_s().write_fmt(args)
+ });
+
if let Err(e) = result {
panic!("failed printing to {}: {}", label, e);
}
data: *mut u8,
data_ptr: *mut usize,
vtable_ptr: *mut usize) -> u32;
- #[unwind]
+ #[cfg_attr(stage0, unwind)]
+ #[cfg_attr(not(stage0), unwind(allowed))]
fn __rust_start_panic(data: usize, vtable: usize) -> u32;
}
/// Entry point of panic from the libcore crate.
#[cfg(not(test))]
#[lang = "panic_fmt"]
-#[unwind]
+#[cfg_attr(stage0, unwind)]
+#[cfg_attr(not(stage0), unwind(allowed))]
pub extern fn rust_begin_panic(msg: fmt::Arguments,
file: &'static str,
line: u32,
}
}
+/// An iterator over [`Path`] and its ancestors.
+///
+/// This `struct` is created by the [`ancestors`] method on [`Path`].
+/// See its documentation for more.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(path_ancestors)]
+///
+/// use std::path::Path;
+///
+/// let path = Path::new("/foo/bar");
+///
+/// for ancestor in path.ancestors() {
+/// println!("{}", ancestor.display());
+/// }
+/// ```
+///
+/// [`ancestors`]: struct.Path.html#method.ancestors
+/// [`Path`]: struct.Path.html
+#[derive(Copy, Clone, Debug)]
+#[unstable(feature = "path_ancestors", issue = "48581")]
+pub struct Ancestors<'a> {
+ next: Option<&'a Path>,
+}
+
+#[unstable(feature = "path_ancestors", issue = "48581")]
+impl<'a> Iterator for Ancestors<'a> {
+ type Item = &'a Path;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let next = self.next;
+ self.next = match next {
+ Some(path) => path.parent(),
+ None => None,
+ };
+ next
+ }
+}
+
+#[unstable(feature = "fused", issue = "35602")]
+impl<'a> FusedIterator for Ancestors<'a> {}
+
////////////////////////////////////////////////////////////////////////////////
// Basic types and traits
////////////////////////////////////////////////////////////////////////////////
})
}
+ /// Produces an iterator over `Path` and its ancestors.
+ ///
+ /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero
+ /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
+ /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
+ /// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
+ /// namely `&self`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(path_ancestors)]
+ ///
+ /// use std::path::Path;
+ ///
+ /// let mut ancestors = Path::new("/foo/bar").ancestors();
+ /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("/foo")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("/")));
+ /// assert_eq!(ancestors.next(), None);
+ /// ```
+ ///
+ /// [`None`]: ../../std/option/enum.Option.html#variant.None
+ /// [`parent`]: struct.Path.html#method.parent
+ #[unstable(feature = "path_ancestors", issue = "48581")]
+ pub fn ancestors(&self) -> Ancestors {
+ Ancestors {
+ next: Some(&self),
+ }
+ }
+
/// Returns the final component of the `Path`, if there is one.
///
/// If the path is a normal file, this is the file name. If it's the path of a directory, this
}
}
-/// Indicator of the state of a thread local storage key.
-#[unstable(feature = "thread_local_state",
- reason = "state querying was recently added",
- issue = "27716")]
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-pub enum LocalKeyState {
- /// All keys are in this state whenever a thread starts. Keys will
- /// transition to the `Valid` state once the first call to [`with`] happens
- /// and the initialization expression succeeds.
- ///
- /// Keys in the `Uninitialized` state will yield a reference to the closure
- /// passed to [`with`] so long as the initialization routine does not panic.
- ///
- /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
- Uninitialized,
-
- /// Once a key has been accessed successfully, it will enter the `Valid`
- /// state. Keys in the `Valid` state will remain so until the thread exits,
- /// at which point the destructor will be run and the key will enter the
- /// `Destroyed` state.
- ///
- /// Keys in the `Valid` state will be guaranteed to yield a reference to the
- /// closure passed to [`with`].
- ///
- /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
- Valid,
-
- /// When a thread exits, the destructors for keys will be run (if
- /// necessary). While a destructor is running, and possibly after a
- /// destructor has run, a key is in the `Destroyed` state.
- ///
- /// Keys in the `Destroyed` states will trigger a panic when accessed via
- /// [`with`].
- ///
- /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
- Destroyed,
-}
-
/// An error returned by [`LocalKey::try_with`](struct.LocalKey.html#method.try_with).
-#[unstable(feature = "thread_local_state",
- reason = "state querying was recently added",
- issue = "27716")]
+#[stable(feature = "thread_local_try_with", since = "1.26.0")]
pub struct AccessError {
_private: (),
}
-#[unstable(feature = "thread_local_state",
- reason = "state querying was recently added",
- issue = "27716")]
+#[stable(feature = "thread_local_try_with", since = "1.26.0")]
impl fmt::Debug for AccessError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("AccessError").finish()
}
}
-#[unstable(feature = "thread_local_state",
- reason = "state querying was recently added",
- issue = "27716")]
+#[stable(feature = "thread_local_try_with", since = "1.26.0")]
impl fmt::Display for AccessError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt("already destroyed", f)
(*ptr).as_ref().unwrap()
}
- /// Query the current state of this key.
- ///
- /// A key is initially in the `Uninitialized` state whenever a thread
- /// starts. It will remain in this state up until the first call to [`with`]
- /// within a thread has run the initialization expression successfully.
- ///
- /// Once the initialization expression succeeds, the key transitions to the
- /// `Valid` state which will guarantee that future calls to [`with`] will
- /// succeed within the thread. Some keys might skip the `Uninitialized`
- /// state altogether and start in the `Valid` state as an optimization
- /// (e.g. keys initialized with a constant expression), but no guarantees
- /// are made.
- ///
- /// When a thread exits, each key will be destroyed in turn, and as keys are
- /// destroyed they will enter the `Destroyed` state just before the
- /// destructor starts to run. Keys may remain in the `Destroyed` state after
- /// destruction has completed. Keys without destructors (e.g. with types
- /// that are [`Copy`]), may never enter the `Destroyed` state.
- ///
- /// Keys in the `Uninitialized` state can be accessed so long as the
- /// initialization does not panic. Keys in the `Valid` state are guaranteed
- /// to be able to be accessed. Keys in the `Destroyed` state will panic on
- /// any call to [`with`].
- ///
- /// [`with`]: ../../std/thread/struct.LocalKey.html#method.with
- /// [`Copy`]: ../../std/marker/trait.Copy.html
- #[unstable(feature = "thread_local_state",
- reason = "state querying was recently added",
- issue = "27716")]
- pub fn state(&'static self) -> LocalKeyState {
- unsafe {
- match (self.inner)() {
- Some(cell) => {
- match *cell.get() {
- Some(..) => LocalKeyState::Valid,
- None => LocalKeyState::Uninitialized,
- }
- }
- None => LocalKeyState::Destroyed,
- }
- }
- }
-
/// Acquires a reference to the value in this TLS key.
///
/// This will lazily initialize the value if this thread has not referenced
/// this key yet. If the key has been destroyed (which may happen if this is called
- /// in a destructor), this function will return a ThreadLocalError.
+ /// in a destructor), this function will return a `ThreadLocalError`.
///
/// # Panics
///
/// This function will still `panic!()` if the key is uninitialized and the
/// key's initializer panics.
- #[unstable(feature = "thread_local_state",
- reason = "state querying was recently added",
- issue = "27716")]
+ #[stable(feature = "thread_local_try_with", since = "1.26.0")]
pub fn try_with<F, R>(&'static self, f: F) -> Result<R, AccessError>
- where F: FnOnce(&T) -> R {
+ where
+ F: FnOnce(&T) -> R,
+ {
unsafe {
let slot = (self.inner)().ok_or(AccessError {
_private: (),
mod tests {
use sync::mpsc::{channel, Sender};
use cell::{Cell, UnsafeCell};
- use super::LocalKeyState;
use thread;
struct Foo(Sender<()>);
struct Foo;
impl Drop for Foo {
fn drop(&mut self) {
- assert!(FOO.state() == LocalKeyState::Destroyed);
+ assert!(FOO.try_with(|_| ()).is_err());
}
}
- fn foo() -> Foo {
- assert!(FOO.state() == LocalKeyState::Uninitialized);
- Foo
- }
- thread_local!(static FOO: Foo = foo());
+ thread_local!(static FOO: Foo = Foo);
thread::spawn(|| {
- assert!(FOO.state() == LocalKeyState::Uninitialized);
- FOO.with(|_| {
- assert!(FOO.state() == LocalKeyState::Valid);
- });
- assert!(FOO.state() == LocalKeyState::Valid);
+ assert!(FOO.try_with(|_| ()).is_ok());
}).join().ok().unwrap();
}
fn drop(&mut self) {
unsafe {
HITS += 1;
- if K2.state() == LocalKeyState::Destroyed {
+ if K2.try_with(|_| ()).is_err() {
assert_eq!(HITS, 3);
} else {
if HITS == 1 {
fn drop(&mut self) {
unsafe {
HITS += 1;
- assert!(K1.state() != LocalKeyState::Destroyed);
+ assert!(K1.try_with(|_| ()).is_ok());
assert_eq!(HITS, 2);
K1.with(|s| *s.get() = Some(S1));
}
impl Drop for S1 {
fn drop(&mut self) {
- assert!(K1.state() == LocalKeyState::Destroyed);
+ assert!(K1.try_with(|_| ()).is_err());
}
}
fn drop(&mut self) {
let S1(ref tx) = *self;
unsafe {
- if K2.state() != LocalKeyState::Destroyed {
- K2.with(|s| *s.get() = Some(Foo(tx.clone())));
- }
+ let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone())));
}
}
}
#[macro_use] mod local;
#[stable(feature = "rust1", since = "1.0.0")]
-pub use self::local::{LocalKey, LocalKeyState, AccessError};
+pub use self::local::{LocalKey, AccessError};
// The types used by the thread_local! macro to access TLS keys. Note that there
// are two types, the "OS" type and the "fast" type. The OS thread local key
PatKind::TupleStruct(_, ref s, _) | PatKind::Tuple(ref s, _) => {
s.iter().all(|p| p.walk(it))
}
- PatKind::Box(ref s) | PatKind::Ref(ref s, _) => {
+ PatKind::Box(ref s) | PatKind::Ref(ref s, _) | PatKind::Paren(ref s) => {
s.walk(it)
}
PatKind::Slice(ref before, ref slice, ref after) => {
/// `[a, b, ..i, y, z]` is represented as:
/// `PatKind::Slice(box [a, b], Some(i), box [y, z])`
Slice(Vec<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
+ /// Parentheses in patters used for grouping, i.e. `(PAT)`.
+ Paren(P<Pat>),
/// A macro pattern; pre-expansion
Mac(Mac),
}
})
}
+#[derive(Copy, Clone, PartialEq)]
+pub enum UnwindAttr {
+ Allowed,
+ Aborts,
+}
+
+/// Determine what `#[unwind]` attribute is present in `attrs`, if any.
+pub fn find_unwind_attr(diagnostic: Option<&Handler>, attrs: &[Attribute]) -> Option<UnwindAttr> {
+ let syntax_error = |attr: &Attribute| {
+ mark_used(attr);
+ diagnostic.map(|d| {
+ span_err!(d, attr.span, E0633, "malformed `#[unwind]` attribute");
+ });
+ None
+ };
+
+ attrs.iter().fold(None, |ia, attr| {
+ if attr.path != "unwind" {
+ return ia;
+ }
+ let meta = match attr.meta() {
+ Some(meta) => meta.node,
+ None => return ia,
+ };
+ match meta {
+ MetaItemKind::Word => {
+ syntax_error(attr)
+ }
+ MetaItemKind::List(ref items) => {
+ mark_used(attr);
+ if items.len() != 1 {
+ syntax_error(attr)
+ } else if list_contains_name(&items[..], "allowed") {
+ Some(UnwindAttr::Allowed)
+ } else if list_contains_name(&items[..], "aborts") {
+ Some(UnwindAttr::Aborts)
+ } else {
+ syntax_error(attr)
+ }
+ }
+ _ => ia,
+ }
+ })
+}
+
/// True if `#[inline]` or `#[inline(always)]` is present in `attrs`.
pub fn requests_inline(attrs: &[Attribute]) -> bool {
match find_inline_attr(None, attrs) {
pub(super) files: RefCell<Vec<Rc<FileMap>>>,
file_loader: Box<FileLoader>,
// This is used to apply the file path remapping as specified via
- // -Zremap-path-prefix to all FileMaps allocated within this CodeMap.
+ // --remap-path-prefix to all FileMaps allocated within this CodeMap.
path_mapping: FilePathMapping,
stable_id_to_filemap: RefCell<FxHashMap<StableFilemapId, Rc<FileMap>>>,
/// In case we are in a doctest, replace all file names with the PathBuf,
};
debug!("find_width_of_character_at_span: snippet=`{:?}`", snippet);
- let file_start_pos = local_begin.fm.start_pos.to_usize();
- let file_end_pos = local_begin.fm.end_pos.to_usize();
- debug!("find_width_of_character_at_span: file_start_pos=`{:?}` file_end_pos=`{:?}`",
- file_start_pos, file_end_pos);
-
let mut target = if forwards { end_index + 1 } else { end_index - 1 };
debug!("find_width_of_character_at_span: initial target=`{:?}`", target);
- while !snippet.is_char_boundary(target - start_index)
- && target >= file_start_pos && target <= file_end_pos {
- target = if forwards { target + 1 } else { target - 1 };
+ while !snippet.is_char_boundary(target - start_index) && target < source_len {
+ target = if forwards {
+ target + 1
+ } else {
+ match target.checked_sub(1) {
+ Some(target) => target,
+ None => {
+ break;
+ }
+ }
+ };
debug!("find_width_of_character_at_span: target=`{:?}`", target);
}
debug!("find_width_of_character_at_span: final target=`{:?}`", target);
```
"##,
+E0633: r##"
+The `unwind` attribute was malformed.
+
+Erroneous code example:
+
+```ignore (compile_fail not working here; see Issue #43707)
+#[unwind()] // error: expected one argument
+pub extern fn something() {}
+
+fn main() {}
+```
+
+The `#[unwind]` attribute should be used as follows:
+
+- `#[unwind(aborts)]` -- specifies that if a non-Rust ABI function
+ should abort the process if it attempts to unwind. This is the safer
+ and preferred option.
+
+- `#[unwind(allowed)]` -- specifies that a non-Rust ABI function
+ should be allowed to unwind. This can easily result in Undefined
+ Behavior (UB), so be careful.
+
+NB. The default behavior here is "allowed", but this is unspecified
+and likely to change in the future.
+
+"##,
+
}
register_diagnostics! {
// allow `extern "platform-intrinsic" { ... }`
(active, platform_intrinsics, "1.4.0", Some(27731)),
- // allow `#[unwind]`
+ // allow `#[unwind(..)]`
// rust runtime internal
(active, unwind_attributes, "1.4.0", None),
// Multiple patterns with `|` in `if let` and `while let`
(active, if_while_or_patterns, "1.26.0", Some(48215)),
+
+ // Parentheses in patterns
+ (active, pattern_parentheses, "1.26.0", None),
);
declare_features! (
gate_feature_post!(&self, dotdoteq_in_patterns, pattern.span,
"`..=` syntax in patterns is experimental");
}
+ PatKind::Paren(..) => {
+ gate_feature_post!(&self, pattern_parentheses, pattern.span,
+ "parentheses in patterns are unstable");
+ }
_ => {}
}
visit::walk_pat(self, pattern)
slice.map(|x| folder.fold_pat(x)),
after.move_map(|x| folder.fold_pat(x)))
}
+ PatKind::Paren(inner) => PatKind::Paren(folder.fold_pat(inner)),
PatKind::Mac(mac) => PatKind::Mac(folder.fold_mac(mac))
},
span: folder.new_span(span)
};
}
- fn parse_pat_tuple_elements(&mut self, unary_needs_comma: bool)
- -> PResult<'a, (Vec<P<Pat>>, Option<usize>)> {
- let mut fields = vec![];
- let mut ddpos = None;
+ // Parses a parenthesized list of patterns like
+ // `()`, `(p)`, `(p,)`, `(p, q)`, or `(p, .., q)`. Returns:
+ // - a vector of the patterns that were parsed
+ // - an option indicating the index of the `..` element
+ // - a boolean indicating whether a trailing comma was present.
+ // Trailing commas are significant because (p) and (p,) are different patterns.
+ fn parse_parenthesized_pat_list(&mut self) -> PResult<'a, (Vec<P<Pat>>, Option<usize>, bool)> {
+ self.expect(&token::OpenDelim(token::Paren))?;
- while !self.check(&token::CloseDelim(token::Paren)) {
- if ddpos.is_none() && self.eat(&token::DotDot) {
- ddpos = Some(fields.len());
- if self.eat(&token::Comma) {
- // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
- fields.push(self.parse_pat()?);
+ let mut fields = Vec::new();
+ let mut ddpos = None;
+ let mut trailing_comma = false;
+ loop {
+ if self.eat(&token::DotDot) {
+ if ddpos.is_none() {
+ ddpos = Some(fields.len());
+ } else {
+ // Emit a friendly error, ignore `..` and continue parsing
+ self.span_err(self.prev_span,
+ "`..` can only be used once per tuple or tuple struct pattern");
}
- } else if ddpos.is_some() && self.eat(&token::DotDot) {
- // Emit a friendly error, ignore `..` and continue parsing
- self.span_err(self.prev_span, "`..` can only be used once per \
- tuple or tuple struct pattern");
- } else {
+ } else if !self.check(&token::CloseDelim(token::Paren)) {
fields.push(self.parse_pat()?);
+ } else {
+ break
}
- if !self.check(&token::CloseDelim(token::Paren)) ||
- (unary_needs_comma && fields.len() == 1 && ddpos.is_none()) {
- self.expect(&token::Comma)?;
+ trailing_comma = self.eat(&token::Comma);
+ if !trailing_comma {
+ break
}
}
- Ok((fields, ddpos))
+ if ddpos == Some(fields.len()) && trailing_comma {
+ // `..` needs to be followed by `)` or `, pat`, `..,)` is disallowed.
+ self.span_err(self.prev_span, "trailing comma is not permitted after `..`");
+ }
+
+ self.expect(&token::CloseDelim(token::Paren))?;
+
+ Ok((fields, ddpos, trailing_comma))
}
fn parse_pat_vec_elements(
}
token::OpenDelim(token::Paren) => {
// Parse (pat,pat,pat,...) as tuple pattern
- self.bump();
- let (fields, ddpos) = self.parse_pat_tuple_elements(true)?;
- self.expect(&token::CloseDelim(token::Paren))?;
- pat = PatKind::Tuple(fields, ddpos);
+ let (fields, ddpos, trailing_comma) = self.parse_parenthesized_pat_list()?;
+ pat = if fields.len() == 1 && ddpos.is_none() && !trailing_comma {
+ PatKind::Paren(fields.into_iter().nth(0).unwrap())
+ } else {
+ PatKind::Tuple(fields, ddpos)
+ };
}
token::OpenDelim(token::Bracket) => {
// Parse [pat,pat,...] as slice pattern
return Err(self.fatal("unexpected `(` after qualified path"));
}
// Parse tuple struct or enum pattern
- self.bump();
- let (fields, ddpos) = self.parse_pat_tuple_elements(false)?;
- self.expect(&token::CloseDelim(token::Paren))?;
+ let (fields, ddpos, _) = self.parse_parenthesized_pat_list()?;
pat = PatKind::TupleStruct(path, fields, ddpos)
}
_ => pat = PatKind::Path(qself, path),
|s, p| s.print_pat(p))?;
self.s.word("]")?;
}
+ PatKind::Paren(ref inner) => {
+ self.popen()?;
+ self.print_pat(inner)?;
+ self.pclose()?;
+ }
PatKind::Mac(ref m) => self.print_mac(m, token::Paren)?,
}
self.ann.post(self, NodePat(pat))
walk_list!(visitor, visit_pat, tuple_elements);
}
PatKind::Box(ref subpattern) |
- PatKind::Ref(ref subpattern, _) => {
+ PatKind::Ref(ref subpattern, _) |
+ PatKind::Paren(ref subpattern) => {
visitor.visit_pat(subpattern)
}
PatKind::Ident(_, ref pth1, ref optional_subpattern) => {
/// originate from files has names between angle brackets by convention,
/// e.g. `<anon>`
pub name: FileName,
- /// True if the `name` field above has been modified by -Zremap-path-prefix
+ /// True if the `name` field above has been modified by --remap-path-prefix
pub name_was_remapped: bool,
/// The unmapped path of the file that the source came from.
/// Set to `None` if the FileMap was imported from an external crate.
pub type _Unwind_Exception_Cleanup_Fn = extern "C" fn(unwind_code: _Unwind_Reason_Code,
exception: *mut _Unwind_Exception);
extern "C" {
- #[unwind]
+ #[cfg_attr(stage0, unwind)]
+ #[cfg_attr(not(stage0), unwind(allowed))]
pub fn _Unwind_Resume(exception: *mut _Unwind_Exception) -> !;
pub fn _Unwind_DeleteException(exception: *mut _Unwind_Exception);
pub fn _Unwind_GetLanguageSpecificData(ctx: *mut _Unwind_Context) -> *mut c_void;
if #[cfg(not(all(target_os = "ios", target_arch = "arm")))] {
// Not 32-bit iOS
extern "C" {
- #[unwind]
+ #[cfg_attr(stage0, unwind)]
+ #[cfg_attr(not(stage0), unwind(allowed))]
pub fn _Unwind_RaiseException(exception: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
pub fn _Unwind_Backtrace(trace: _Unwind_Trace_Fn,
trace_argument: *mut c_void)
} else {
// 32-bit iOS uses SjLj and does not provide _Unwind_Backtrace()
extern "C" {
- #[unwind]
+ #[cfg_attr(stage0, unwind)]
+ #[cfg_attr(not(stage0), unwind(allowed))]
pub fn _Unwind_SjLj_RaiseException(e: *mut _Unwind_Exception) -> _Unwind_Reason_Code;
}
fn extern_fn();
// CHECK-NOT: Function Attrs: nounwind
// CHECK: declare void @unwinding_extern_fn
- #[unwind]
+ #[unwind(allowed)]
fn unwinding_extern_fn();
}
// ignore-tidy-linelength
-// compile-flags: -g -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/aux-cwd -Zremap-path-prefix-from={{src-base}}/remap_path_prefix/auxiliary -Zremap-path-prefix-to=/the/aux-src
+// compile-flags: -g --remap-path-prefix={{cwd}}=/the/aux-cwd --remap-path-prefix={{src-base}}/remap_path_prefix/auxiliary=/the/aux-src
#[inline]
pub fn some_aux_function() -> i32 {
// ignore-windows
// ignore-tidy-linelength
-// compile-flags: -g -C no-prepopulate-passes -Zremap-path-prefix-from={{cwd}} -Zremap-path-prefix-to=/the/cwd -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
+// compile-flags: -g -C no-prepopulate-passes --remap-path-prefix={{cwd}}=/the/cwd --remap-path-prefix={{src-base}}=/the/src
// aux-build:remap_path_prefix_aux.rs
extern crate remap_path_prefix_aux;
// except according to those terms.
#![feature(dyn_trait)]
+#![allow(bare_trait_object)]
struct Foo;
//[rpass1] compile-flags: -g
//[rpass2] compile-flags: -g
-//[rpass3] compile-flags: -g -Zremap-path-prefix-from={{src-base}} -Zremap-path-prefix-to=/the/src
+//[rpass3] compile-flags: -g --remap-path-prefix={{src-base}}=/the/src
#![feature(rustc_attrs)]
#![crate_type="rlib"]
// nop;
// _0 = ();
// END rustc.move_out_by_subslice.UniformArrayMoveOut.after.mir
+
+// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
+// StorageLive(_6);
+// StorageLive(_7);
+// _7 = move _1[0 of 2];
+// StorageLive(_8);
+// _8 = move _1[1 of 2];
+// _6 = [move _7, move _8];
+// StorageDead(_7);
+// StorageDead(_8);
+// _0 = ();
+// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.before.mir
+
+// START rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
+// StorageLive(_6);
+// nop;
+// nop;
+// nop;
+// nop;
+// _6 = move _1[0:];
+// nop;
+// nop;
+// nop;
+// _0 = ();
+// END rustc.move_out_by_subslice.RestoreSubsliceArrayMoveOut.after.mir
fn main() {
match 0 {
- (pat, ..,) => {} //~ ERROR expected pattern, found `)`
+ (pat, ..,) => {} //~ ERROR trailing comma is not permitted after `..`
}
}
+++ /dev/null
-// Copyright 2016 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.
-
-// compile-flags: -Z parse-only
-
-fn main() {
- match 0 {
- (pat) => {} //~ ERROR expected one of `,` or `@`, found `)`
- }
-}
--- /dev/null
+-include ../tools.mk
+
+all: $(call NATIVE_STATICLIB,foo)
+ $(RUSTC) main.rs
+ $(call RUN,main)
--- /dev/null
+// 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.
+
+#include <assert.h>
+#include <setjmp.h>
+
+static jmp_buf ENV;
+
+extern void test_middle();
+
+void test_start(void(*f)()) {
+ if (setjmp(ENV) != 0)
+ return;
+ f();
+ assert(0);
+}
+
+void test_end() {
+ longjmp(ENV, 1);
+ assert(0);
+}
--- /dev/null
+// 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.
+
+#[link(name = "foo", kind = "static")]
+extern {
+ fn test_start(f: extern fn());
+ fn test_end();
+}
+
+fn main() {
+ unsafe {
+ test_start(test_middle);
+ }
+}
+
+struct A;
+
+impl Drop for A {
+ fn drop(&mut self) {
+ }
+}
+
+extern fn test_middle() {
+ let _a = A;
+ foo();
+}
+
+fn foo() {
+ let _a = A;
+ unsafe {
+ test_end();
+ }
+}
// ignore-cloudabi no env and process
// ignore-emscripten no processes
+#![feature(unwind_attributes)]
+
use std::{env, panic};
use std::io::prelude::*;
use std::io;
use std::process::{Command, Stdio};
+#[unwind(aborts)]
extern "C" fn panic_in_ffi() {
panic!("Test");
}
--- /dev/null
+// Copyright 2017 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.
+
+trait Trait<T> {}
+struct Foo<U, V=i32>(U, V) where U: Trait<V>;
+
+trait Marker {}
+struct TwoParams<T, U>(T, U);
+impl Marker for TwoParams<i32, i32> {}
+
+// Clauses with more than 1 param are not checked.
+struct IndividuallyBogus<T = i32, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Marker;
+struct BogusTogether<T = u32, U = i32>(T, U) where TwoParams<T, U>: Marker;
+// Clauses with non-defaulted params are not checked.
+struct NonDefaultedInClause<T, U = i32>(TwoParams<T, U>) where TwoParams<T, U>: Marker;
+struct DefaultedLhs<U, V=i32>(U, V) where V: Trait<U>;
+// Dependent defaults are not checked.
+struct Dependent<T, U = T>(T, U) where U: Copy;
+trait SelfBound<T: Copy=Self> {}
+// Not even for well-formedness.
+struct WellFormedProjection<A, T=<A as Iterator>::Item>(A, T);
+
+fn main() {}
--- /dev/null
+// 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.
+
+// ignore-test Not a test. Used by issue-48508.rs
+
+pub fn other() -> f64 {
+ let ยต = 1.0;
+ ยต
+}
--- /dev/null
+// 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.
+
+// Regression test for issue #48508:
+//
+// Confusion between global and local file offsets caused incorrect handling of multibyte character
+// spans when compiling multiple files. One visible effect was an ICE generating debug information
+// when a multibyte character is at the end of a scope. The problematic code is actually in
+// issue-48508-aux.rs
+
+// compile-flags:-g
+// ignore-pretty issue #37195
+
+#![feature(non_ascii_idents)]
+
+#[path = "issue-48508-aux.rs"]
+mod other_file;
+
+fn main() {
+ other_file::other();
+}
--- /dev/null
+// 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.
+
+// Regression test for #48551. Covers a case where duplicate candidates
+// arose during associated type projection.
+
+use std::ops::{Mul, MulAssign};
+
+pub trait ClosedMul<Right>: Sized + Mul<Right, Output = Self> + MulAssign<Right> {}
+impl<T, Right> ClosedMul<Right> for T
+where
+ T: Mul<Right, Output = T> + MulAssign<Right>,
+{
+}
+
+pub trait InnerSpace: ClosedMul<<Self as InnerSpace>::Real> {
+ type Real;
+}
+
+pub trait FiniteDimVectorSpace: ClosedMul<<Self as FiniteDimVectorSpace>::Field> {
+ type Field;
+}
+
+pub trait FiniteDimInnerSpace
+ : InnerSpace + FiniteDimVectorSpace<Field = <Self as InnerSpace>::Real> {
+}
+
+pub trait EuclideanSpace: ClosedMul<<Self as EuclideanSpace>::Real> {
+ type Coordinates: FiniteDimInnerSpace<Real = Self::Real>
+ + Mul<Self::Real, Output = Self::Coordinates>
+ + MulAssign<Self::Real>;
+
+ type Real;
+}
+
+fn main() {}
--- /dev/null
+// Copyright 2016 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.
+
+#![feature(pattern_parentheses)]
+
+fn main() {
+ match 0 {
+ (pat) => assert_eq!(pat, 0)
+ }
+}
// ignore-emscripten no threads support
-#![feature(thread_local_state)]
+#![feature(thread_local_try_with)]
-use std::thread::{self, LocalKeyState};
+use std::thread;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
struct Foo { cnt: usize }
FOO.with(|foo| assert_eq!(foo.cnt, 0));
} else {
assert_eq!(self.cnt, 0);
- match FOO.state() {
- LocalKeyState::Valid => panic!("should not be in valid state"),
- LocalKeyState::Uninitialized |
- LocalKeyState::Destroyed => {}
+ if FOO.try_with(|_| ()).is_ok() {
+ panic!("should not be in valid state");
}
}
}
// ignore-emscripten no threads support
-#![feature(thread_local_state)]
+#![feature(thread_local_try_with)]
use std::thread;
}
trait Trait<T> {}
+impl Trait<i32> for i32 {}
impl Foo for Bar {} //~ ERROR E0404
-fn main() {
-}
+fn main() {}
+
+fn baz<T: Foo>(_: T) {} //~ ERROR E0404
LL | impl Foo for Bar {} //~ ERROR E0404
| ^^^ not a trait
+error[E0404]: expected trait, found struct `Foo`
+ --> $DIR/E0404.rs:18:11
+ |
+LL | fn baz<T: Foo>(_: T) {} //~ ERROR E0404
+ | ^^^ not a trait
+
error: cannot continue compilation due to previous error
If you want more information on this error, try using "rustc --explain E0404"
--- /dev/null
+// Copyright 2017 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.
+
+fn main() {
+ match 0 {
+ (pat) => {} //~ ERROR parentheses in patterns are unstable
+ }
+}
--- /dev/null
+error[E0658]: parentheses in patterns are unstable
+ --> $DIR/feature-gate-pattern_parentheses.rs:13:9
+ |
+LL | (pat) => {} //~ ERROR parentheses in patterns are unstable
+ | ^^^^^
+ |
+ = help: add #![feature(pattern_parentheses)] to the crate attributes to enable
+
+error: aborting due to previous error
+
+If you want more information on this error, try using "rustc --explain E0658"
--- /dev/null
+// Copyright 2017 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.
+
+use std::iter::FromIterator;
+use std::vec::IntoIter;
+use std::ops::Add;
+
+struct Foo<T, U: FromIterator<T>>(T, U);
+struct WellFormed<Z = Foo<i32, i32>>(Z);
+//~^ error: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfied [E0277]
+struct WellFormedNoBounds<Z:?Sized = Foo<i32, i32>>(Z);
+//~^ error: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfied [E0277]
+
+struct Bounds<T:Copy=String>(T);
+//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277]
+
+struct WhereClause<T=String>(T) where T: Copy;
+//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277]
+
+trait TraitBound<T:Copy=String> {}
+//~^ error: the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277]
+
+trait Super<T: Copy> { }
+trait Base<T = String>: Super<T> { }
+//~^ error: the trait bound `T: std::marker::Copy` is not satisfied [E0277]
+
+trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
+//~^ error: cannot add `u8` to `i32` [E0277]
+
+fn main() { }
--- /dev/null
+error[E0277]: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfied
+ --> $DIR/type-check-defaults.rs:16:19
+ |
+LL | struct WellFormed<Z = Foo<i32, i32>>(Z);
+ | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32`
+ |
+ = help: the trait `std::iter::FromIterator<i32>` is not implemented for `i32`
+note: required by `Foo`
+ --> $DIR/type-check-defaults.rs:15:1
+ |
+LL | struct Foo<T, U: FromIterator<T>>(T, U);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `i32: std::iter::FromIterator<i32>` is not satisfied
+ --> $DIR/type-check-defaults.rs:18:27
+ |
+LL | struct WellFormedNoBounds<Z:?Sized = Foo<i32, i32>>(Z);
+ | ^ a collection of type `i32` cannot be built from an iterator over elements of type `i32`
+ |
+ = help: the trait `std::iter::FromIterator<i32>` is not implemented for `i32`
+note: required by `Foo`
+ --> $DIR/type-check-defaults.rs:15:1
+ |
+LL | struct Foo<T, U: FromIterator<T>>(T, U);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
+ --> $DIR/type-check-defaults.rs:21:1
+ |
+LL | struct Bounds<T:Copy=String>(T);
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
+ |
+ = note: required by `std::marker::Copy`
+
+error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
+ --> $DIR/type-check-defaults.rs:24:1
+ |
+LL | struct WhereClause<T=String>(T) where T: Copy;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
+ |
+ = note: required by `std::marker::Copy`
+
+error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied
+ --> $DIR/type-check-defaults.rs:27:1
+ |
+LL | trait TraitBound<T:Copy=String> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String`
+ |
+ = note: required by `std::marker::Copy`
+
+error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
+ --> $DIR/type-check-defaults.rs:31:1
+ |
+LL | trait Base<T = String>: Super<T> { }
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+ |
+ = help: consider adding a `where T: std::marker::Copy` bound
+note: required by `Super`
+ --> $DIR/type-check-defaults.rs:30:1
+ |
+LL | trait Super<T: Copy> { }
+ | ^^^^^^^^^^^^^^^^^^^^
+
+error[E0277]: cannot add `u8` to `i32`
+ --> $DIR/type-check-defaults.rs:34:1
+ |
+LL | trait ProjectionPred<T:Iterator = IntoIter<i32>> where T::Item : Add<u8> {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u8`
+ |
+ = help: the trait `std::ops::Add<u8>` is not implemented for `i32`
+ = note: required by `std::ops::Add`
+
+error: aborting due to 7 previous errors
+
+If you want more information on this error, try using "rustc --explain E0277"
import copy
import datetime
import collections
+import textwrap
+try:
+ import urllib2
+except ImportError:
+ import urllib.request as urllib2
# List of people to ping when the status of a tool changed.
MAINTAINERS = {
'clippy-driver': '@Manishearth @llogiq @mcarton @oli-obk',
'rls': '@nrc',
'rustfmt': '@nrc',
+ 'book': '@carols10cents @steveklabnik',
+ 'nomicon': '@frewsxcv @Gankro',
+ 'reference': '@steveklabnik @Havvy @matthewjasper @alercah',
+ 'rust-by-example': '@steveklabnik @marioidival @projektir',
}
return {}
-def update_latest(current_commit, relevant_pr_number, current_datetime):
+def update_latest(
+ current_commit,
+ relevant_pr_number,
+ relevant_pr_url,
+ current_datetime
+):
'''Updates `_data/latest.json` to match build result of the given commit.
'''
with open('_data/latest.json', 'rb+') as f:
}
slug = 'rust-lang/rust'
- message = '๐ฃ Toolstate changed by {}!\n\nTested on commit {}@{}.\n\n' \
- .format(relevant_pr_number, slug, current_commit)
+ message = textwrap.dedent('''\
+ ๐ฃ Toolstate changed by {}!
+
+ Tested on commit {}@{}.
+ Direct link to PR: <{}>
+
+ ''').format(relevant_pr_number, slug, current_commit, relevant_pr_url)
anything_changed = False
for status in latest:
tool = status['tool']
elif new < old:
changed = True
message += '๐ {} on {}: {} โ {} (cc {}).\n' \
- .format(tool, os, old, new, MAINTAINERS[tool])
+ .format(tool, os, old, new, MAINTAINERS.get(tool))
if changed:
status['commit'] = current_commit
cur_datetime = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
cur_commit_msg = sys.argv[2]
save_message_to_path = sys.argv[3]
+ github_token = sys.argv[4]
- relevant_pr_match = re.search('#[0-9]+', cur_commit_msg)
+ relevant_pr_match = re.search('#([0-9]+)', cur_commit_msg)
if relevant_pr_match:
- relevant_pr_number = 'rust-lang/rust' + relevant_pr_match.group(0)
+ number = relevant_pr_match.group(1)
+ relevant_pr_number = 'rust-lang/rust#' + number
+ relevant_pr_url = 'https://github.com/rust-lang/rust/pull/' + number
else:
+ number = '-1'
relevant_pr_number = '<unknown PR>'
-
- message = update_latest(cur_commit, relevant_pr_number, cur_datetime)
- if message:
- print(message)
- with open(save_message_to_path, 'w') as f:
- f.write(message)
- else:
+ relevant_pr_url = '<unknown>'
+
+ message = update_latest(
+ cur_commit,
+ relevant_pr_number,
+ relevant_pr_url,
+ cur_datetime
+ )
+ if not message:
print('<Nothing changed>')
+ sys.exit(0)
+
+ print(message)
+ with open(save_message_to_path, 'w') as f:
+ f.write(message)
+
+ # Write the toolstate comment on the PR as well.
+ gh_url = 'https://api.github.com/repos/rust-lang/rust/issues/{}/comments' \
+ .format(number)
+ response = urllib2.urlopen(urllib2.Request(
+ gh_url,
+ json.dumps({'body': message}),
+ {
+ 'Authorization': 'token ' + github_token,
+ 'Content-Type': 'application/json',
+ }
+ ))
+ response.read()
-Subproject commit f01491115e821e10217574ad4091b08015b7b1c8
+Subproject commit d4f0b29d0ce01f0716d3b147d68125d520b63ae5