]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #44418 - alexcrichton:remove-dep-graph, r=michaelwoerister
authorbors <bors@rust-lang.org>
Sun, 10 Sep 2017 07:33:46 +0000 (07:33 +0000)
committerbors <bors@rust-lang.org>
Sun, 10 Sep 2017 07:33:46 +0000 (07:33 +0000)
rustc: Remove `DepGraph` handling from rustc_metadata

This should now be entirely tracked through queries, so no need to have a
`DepGraph` in the `CStore` object any more!

cc #44390

36 files changed:
src/Cargo.lock
src/bootstrap/builder.rs
src/bootstrap/check.rs
src/bootstrap/dist.rs
src/bootstrap/tool.rs
src/bootstrap/util.rs
src/libbacktrace/configure
src/libbacktrace/configure.ac
src/libbacktrace/filetype.awk
src/libbacktrace/macho.c [new file with mode: 0644]
src/libcore/cmp.rs
src/librustc/dep_graph/dep_node.rs
src/librustc/infer/mod.rs
src/librustc/infer/resolve.rs
src/librustc/traits/project.rs
src/librustc/ty/mod.rs
src/librustc_mir/transform/qualify_consts.rs
src/librustdoc/Cargo.toml
src/librustdoc/clean/simplify.rs
src/librustdoc/html/markdown.rs
src/libstd/build.rs
src/libstd/f32.rs
src/libstd/f64.rs
src/libstd/lib.rs
src/libstd/sys/unix/backtrace/mod.rs
src/libstd/sys/unix/backtrace/printing/dladdr.rs
src/libstd/sys/unix/backtrace/printing/mod.rs
src/libstd/sys_common/mod.rs
src/test/compile-fail/issue-17718-const-destructors.rs
src/test/compile-fail/static-drop-scope.rs
src/test/run-pass/backtrace-debuginfo.rs
src/test/run-pass/issue-34053.rs
src/test/ui/span/E0493.rs
src/test/ui/span/E0493.stderr
src/tools/cargo
src/tools/rust-installer

index a2ea07f3652ba36c24372800276162de5ce07a07..47ef0a7d8ca13a98f4aef9a61a1463d78d0546d5 100644 (file)
@@ -183,11 +183,11 @@ dependencies = [
  "cargotest 0.1.0",
  "core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "crates-io 0.12.0",
- "crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "crossbeam 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "fs2 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -209,10 +209,10 @@ dependencies = [
  "psapi-sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
  "tar 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -343,7 +343,7 @@ name = "crates-io"
 version = "0.12.0"
 dependencies = [
  "curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
  "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -355,6 +355,11 @@ name = "crossbeam"
 version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 
+[[package]]
+name = "crossbeam"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
 [[package]]
 name = "cssparser"
 version = "0.13.7"
@@ -487,15 +492,7 @@ dependencies = [
 
 [[package]]
 name = "error-chain"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "error-chain"
-version = "0.11.0-rc.2"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "backtrace 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -744,7 +741,7 @@ name = "installer"
 version = "0.0.0"
 dependencies = [
  "clap 2.26.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)",
  "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1868,7 +1865,7 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "0.7.0"
+version = "0.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1906,7 +1903,7 @@ dependencies = [
 
 [[package]]
 name = "serde_ignored"
-version = "0.0.3"
+version = "0.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 dependencies = [
  "serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2451,6 +2448,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum core-foundation 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5909502e547762013619f4c4e01cc7393c20fe2d52d7fa471c1210adb2320dc7"
 "checksum core-foundation-sys 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bc9fb3d6cb663e6fd7cf1c63f9b144ee2b1e4a78595a0451dd34bff85b9a3387"
 "checksum crossbeam 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0c5ea215664ca264da8a9d9c3be80d2eaf30923c259d03e870388eb927508f97"
+"checksum crossbeam 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8837ab96533202c5b610ed44bc7f4183e7957c1c8f56e8cc78bb098593c8ba0a"
 "checksum cssparser 0.13.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef6124306e5ebc5ab11891d063aeafdd0cdc308079b708c8b566125f3680292b"
 "checksum cssparser-macros 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "079adec4af52bb5275eadd004292028c79eb3c5f5b4ee8086a36d4197032f6df"
 "checksum curl 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7034c534a1d7d22f7971d6088aa9d281d219ef724026c3428092500f41ae9c2c"
@@ -2465,8 +2463,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum enum_primitive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "be4551092f4d519593039259a9ed8daedf0da12e5109c5280338073eaeb81180"
 "checksum env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "15abd780e45b3ea4f76b4e9a26ff4843258dd8a3eed2775a0e7368c2e7936c2f"
 "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
-"checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8"
-"checksum error-chain 0.11.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "38d3a55d9a7a456748f2a3912c0941a5d9a68006eb15b3c3c9836b8420dc102d"
+"checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3"
 "checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922"
 "checksum flate2 0.2.19 (registry+https://github.com/rust-lang/crates.io-index)" = "36df0166e856739905cd3d7e0b210fe818592211a008862599845e012d8d304c"
 "checksum fnv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc484842f1e2884faf56f529f960cc12ad8c71ce96cc7abba0a067c98fee344"
@@ -2557,12 +2554,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d"
 "checksum scopeguard 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "59a076157c1e2dc561d8de585151ee6965d910dd4dcb5dabb7ae3e83981a6c57"
 "checksum selectors 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3c89b1c6a3c029c82263f7dd2d44d0005ee7374eb09e254ab59dede4353a8c0"
-"checksum semver 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3fdd61b85a0fa777f7fb7c454b9189b2941b110d1385ce84d7f76efdf1606a85"
+"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
 "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 "checksum serde 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f7726f29ddf9731b17ff113c461e362c381d9d69433f79de4f3dd572488823e9"
 "checksum serde_derive 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cf823e706be268e73e7747b147aa31c8f633ab4ba31f115efb57e5047c3a76dd"
 "checksum serde_derive_internals 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "37aee4e0da52d801acfbc0cc219eb1eda7142112339726e427926a6f6ee65d3a"
-"checksum serde_ignored 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c10e798e4405d7dcec3658989e35ee6706f730a9ed7c1184d5ebd84317e82f46"
+"checksum serde_ignored 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "190e9765dcedb56be63b6e0993a006c7e3b071a016a304736e4a315dc01fb142"
 "checksum serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "48b04779552e92037212c3615370f6bd57a40ebba7f20e554ff9f55e41a69a7b"
 "checksum shell-escape 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd5cc96481d54583947bfe88bf30c23d53f883c6cd0145368b69989d97b84ef8"
 "checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
index 722b3d16e9d19c1bd2e0960ef065b6703bda0c67..4765546b184d39bffa0c1375f8af83da2e9e9b2f 100644 (file)
@@ -251,9 +251,9 @@ macro_rules! describe {
                 tool::RustInstaller, tool::Cargo, tool::Rls, tool::Rustdoc, tool::Clippy,
                 native::Llvm),
             Kind::Test => describe!(check::Tidy, check::Bootstrap, check::DefaultCompiletest,
-                check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Linkcheck,
-                check::Cargotest, check::Cargo, check::Rls, check::Docs, check::ErrorIndex,
-                check::Distcheck),
+                check::HostCompiletest, check::Crate, check::CrateLibrustc, check::Rustdoc,
+                check::Linkcheck, check::Cargotest, check::Cargo, check::Rls, check::Docs,
+                check::ErrorIndex, check::Distcheck),
             Kind::Bench => describe!(check::Crate, check::CrateLibrustc),
             Kind::Doc => describe!(doc::UnstableBook, doc::UnstableBookGen, doc::TheBook,
                 doc::Standalone, doc::Std, doc::Test, doc::Rustc, doc::ErrorIndex, doc::Nomicon,
index 92fb2105b7c5d57133c6425069cc09ae853ae5a8..0d5c3addd9e7447df135a5ac11610f57af94dc1d 100644 (file)
@@ -900,7 +900,6 @@ fn run(self, builder: &Builder) {
     }
 }
 
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub struct Crate {
     compiler: Compiler,
@@ -1080,6 +1079,74 @@ fn run(self, builder: &Builder) {
     }
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub struct Rustdoc {
+    host: Interned<String>,
+    test_kind: TestKind,
+}
+
+impl Step for Rustdoc {
+    type Output = ();
+    const DEFAULT: bool = true;
+    const ONLY_HOSTS: bool = true;
+
+    fn should_run(run: ShouldRun) -> ShouldRun {
+        run.path("src/librustdoc").path("src/tools/rustdoc")
+    }
+
+    fn make_run(run: RunConfig) {
+        let builder = run.builder;
+
+        let test_kind = if builder.kind == Kind::Test {
+            TestKind::Test
+        } else if builder.kind == Kind::Bench {
+            TestKind::Bench
+        } else {
+            panic!("unexpected builder.kind in crate: {:?}", builder.kind);
+        };
+
+        builder.ensure(Rustdoc {
+            host: run.host,
+            test_kind,
+        });
+    }
+
+    fn run(self, builder: &Builder) {
+        let build = builder.build;
+        let test_kind = self.test_kind;
+
+        let compiler = builder.compiler(builder.top_stage, self.host);
+        let target = compiler.host;
+
+        builder.ensure(RemoteCopyLibs { compiler, target });
+
+        let mut cargo = builder.cargo(compiler, Mode::Librustc, target, test_kind.subcommand());
+        compile::rustc_cargo(build, &compiler, target, &mut cargo);
+        let _folder = build.fold_output(|| {
+            format!("{}_stage{}-rustdoc", test_kind.subcommand(), compiler.stage)
+        });
+        println!("{} rustdoc stage{} ({} -> {})", test_kind, compiler.stage,
+                &compiler.host, target);
+
+        if test_kind.subcommand() == "test" && !build.fail_fast {
+            cargo.arg("--no-fail-fast");
+        }
+
+        cargo.arg("-p").arg("rustdoc:0.0.0");
+
+        cargo.arg("--");
+        cargo.args(&build.config.cmd.test_args());
+
+        if build.config.quiet_tests {
+            cargo.arg("--quiet");
+        }
+
+        let _time = util::timeit();
+
+        try_run(build, &mut cargo);
+    }
+}
+
 fn envify(s: &str) -> String {
     s.chars().map(|c| {
         match c {
index 2ca65396b35944403b814e863ea489538a790590..e18850b08b1670db95e9c43bd8b3f18300dd6691 100644 (file)
@@ -20,7 +20,7 @@
 
 use std::env;
 use std::fs::{self, File};
-use std::io::{Read, Write};
+use std::io::{self, Read, Write};
 use std::path::{PathBuf, Path};
 use std::process::{Command, Stdio};
 
@@ -900,7 +900,11 @@ fn run(self, builder: &Builder) -> PathBuf {
 fn install(src: &Path, dstdir: &Path, perms: u32) {
     let dst = dstdir.join(src.file_name().unwrap());
     t!(fs::create_dir_all(dstdir));
-    t!(fs::copy(src, &dst));
+    {
+        let mut s = t!(fs::File::open(&src));
+        let mut d = t!(fs::File::create(&dst));
+        io::copy(&mut s, &mut d).expect("failed to copy");
+    }
     chmod(&dst, perms);
 }
 
index b129aa113a030ce88ed6818d2e0a3535b08c7111..eaa2b1244236fa59f74c9836229305fd0a704e59 100644 (file)
@@ -62,6 +62,7 @@ struct ToolBuild {
     compiler: Compiler,
     target: Interned<String>,
     tool: &'static str,
+    path: &'static str,
     mode: Mode,
 }
 
@@ -81,6 +82,7 @@ fn run(self, builder: &Builder) -> PathBuf {
         let compiler = self.compiler;
         let target = self.target;
         let tool = self.tool;
+        let path = self.path;
 
         match self.mode {
             Mode::Libstd => builder.ensure(compile::Std { compiler, target }),
@@ -92,7 +94,7 @@ fn run(self, builder: &Builder) -> PathBuf {
         let _folder = build.fold_output(|| format!("stage{}-{}", compiler.stage, tool));
         println!("Building stage{} tool {} ({})", compiler.stage, tool, target);
 
-        let mut cargo = prepare_tool_cargo(builder, compiler, target, tool);
+        let mut cargo = prepare_tool_cargo(builder, compiler, target, path);
         build.run(&mut cargo);
         build.cargo_out(compiler, Mode::Tool, target).join(exe(tool, &compiler.host))
     }
@@ -102,11 +104,11 @@ fn prepare_tool_cargo(
     builder: &Builder,
     compiler: Compiler,
     target: Interned<String>,
-    tool: &'static str,
+    path: &'static str,
 ) -> Command {
     let build = builder.build;
     let mut cargo = builder.cargo(compiler, Mode::Tool, target, "build");
-    let dir = build.src.join("src/tools").join(tool);
+    let dir = build.src.join(path);
     cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
 
     // We don't want to build tools dynamically as they'll be running across
@@ -184,6 +186,7 @@ fn run(self, builder: &Builder) -> PathBuf {
                     target: self.target,
                     tool: $tool_name,
                     mode: $mode,
+                    path: $path,
                 })
             }
         }
@@ -201,7 +204,7 @@ fn run(self, builder: &Builder) -> PathBuf {
     Compiletest, "src/tools/compiletest", "compiletest", Mode::Libtest;
     BuildManifest, "src/tools/build-manifest", "build-manifest", Mode::Libstd;
     RemoteTestClient, "src/tools/remote-test-client", "remote-test-client", Mode::Libstd;
-    RustInstaller, "src/tools/rust-installer", "rust-installer", Mode::Libstd;
+    RustInstaller, "src/tools/rust-installer", "fabricate", Mode::Libstd;
 );
 
 #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
@@ -230,6 +233,7 @@ fn run(self, builder: &Builder) -> PathBuf {
             target: self.target,
             tool: "remote-test-server",
             mode: Mode::Libstd,
+            path: "src/tools/remote-test-server",
         })
     }
 }
@@ -276,7 +280,10 @@ fn run(self, builder: &Builder) -> PathBuf {
         let _folder = build.fold_output(|| format!("stage{}-rustdoc", target_compiler.stage));
         println!("Building rustdoc for stage{} ({})", target_compiler.stage, target_compiler.host);
 
-        let mut cargo = prepare_tool_cargo(builder, build_compiler, target, "rustdoc");
+        let mut cargo = prepare_tool_cargo(builder,
+                                           build_compiler,
+                                           target,
+                                           "src/tools/rustdoc");
         build.run(&mut cargo);
         // Cargo adds a number of paths to the dylib search path on windows, which results in
         // the wrong rustdoc being executed. To avoid the conflicting rustdocs, we name the "tool"
@@ -337,6 +344,7 @@ fn run(self, builder: &Builder) -> PathBuf {
             target: self.target,
             tool: "cargo",
             mode: Mode::Librustc,
+            path: "src/tools/cargo",
         })
     }
 }
@@ -375,6 +383,7 @@ fn run(self, builder: &Builder) -> PathBuf {
             target: self.target,
             tool: "clippy",
             mode: Mode::Librustc,
+            path: "src/tools/clippy",
         })
     }
 }
@@ -417,6 +426,7 @@ fn run(self, builder: &Builder) -> PathBuf {
             target: self.target,
             tool: "rls",
             mode: Mode::Librustc,
+            path: "src/tools/rls",
         })
     }
 }
index 234d937823fb5bfc6d3a1d2024ed6afd7d655653..a521dd09453916b263f081638a70799286608e62 100644 (file)
@@ -34,8 +34,12 @@ pub fn staticlib(name: &str, target: &str) -> String {
 /// Copies a file from `src` to `dst`
 pub fn copy(src: &Path, dst: &Path) {
     let _ = fs::remove_file(&dst);
-    let res = fs::copy(src, dst);
-    if let Err(e) = res {
+    // Attempt to "easy copy" by creating a hard link (symlinks don't work on
+    // windows), but if that fails just fall back to a slow `copy` operation.
+    if let Ok(()) = fs::hard_link(src, dst) {
+        return
+    }
+    if let Err(e) = fs::copy(src, dst) {
         panic!("failed to copy `{}` to `{}`: {}", src.display(),
                dst.display(), e)
     }
@@ -44,7 +48,6 @@ pub fn copy(src: &Path, dst: &Path) {
     let atime = FileTime::from_last_access_time(&metadata);
     let mtime = FileTime::from_last_modification_time(&metadata);
     t!(filetime::set_file_times(dst, atime, mtime));
-
 }
 
 /// Copies the `src` directory recursively to `dst`. Both are assumed to exist
index 47df55c22d67f26749fe13cc70d432998f273431..ed47ba3c2fa0822f621a5db62db529c1b5dd0a13 100755 (executable)
@@ -11844,6 +11844,9 @@ elf*) FORMAT_FILE="elf.lo" ;;
 pecoff) FORMAT_FILE="pecoff.lo"
         backtrace_supports_data=no
        ;;
+macho*) FORMAT_FILE="macho.lo"
+        backtrace_supports_data=no
+        ;;
 *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not determine output file type" >&5
 $as_echo "$as_me: WARNING: could not determine output file type" >&2;}
    FORMAT_FILE="unknown.lo"
index 71e85187ef55a00b29e809c68357bdf331dc7135..7ae21b8d1a68c78bb67af749d939d525c01ed0b0 100644 (file)
@@ -231,6 +231,9 @@ elf*) FORMAT_FILE="elf.lo" ;;
 pecoff) FORMAT_FILE="pecoff.lo"
         backtrace_supports_data=no
        ;;
+macho*) FORMAT_FILE="macho.lo"
+        backtrace_supports_data=no
+        ;;
 *) AC_MSG_WARN([could not determine output file type])
    FORMAT_FILE="unknown.lo"
    backtrace_supported=no
index 57bab797a9a8abc1a1310ec077786f499775cfaa..a5f6c8cc1800f0cb24d415cade2b0905f54a730f 100644 (file)
@@ -3,3 +3,9 @@
 /\177ELF\002/ { if (NR == 1) { print "elf64"; exit } }
 /\114\001/    { if (NR == 1) { print "pecoff"; exit } }
 /\144\206/    { if (NR == 1) { print "pecoff"; exit } }
+/\xFE\xED\xFA\xCE/ { if (NR == 1) { print "macho32"; exit } }
+/\xCE\xFA\xED\xFE/ { if (NR == 1) { print "macho32"; exit } }
+/\xFE\xED\xFA\xCF/ { if (NR == 1) { print "macho64"; exit } }
+/\xCF\xFA\xED\xFE/ { if (NR == 1) { print "macho64"; exit } }
+/\xCA\xFE\xBA\xBE/ { if (NR == 1) { print "macho-fat"; exit } }
+/\xBE\xBA\xFE\xCA/ { if (NR == 1) { print "macho-fat"; exit } }
diff --git a/src/libbacktrace/macho.c b/src/libbacktrace/macho.c
new file mode 100644 (file)
index 0000000..9af14e7
--- /dev/null
@@ -0,0 +1,1416 @@
+/* macho.c -- Get debug data from an Mach-O file for backtraces.
+   Copyright (C) 2012-2016 Free Software Foundation, Inc.
+   Written by John Colanduoni.
+
+   Pending upstream pull request:
+   https://github.com/ianlancetaylor/libbacktrace/pull/2
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+    (1) Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+    (2) Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in
+    the documentation and/or other materials provided with the
+    distribution.
+
+    (3) The name of the author may not be used to
+    endorse or promote products derived from this software without
+    specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.  */
+
+#include "config.h"
+
+/* We can't use autotools to detect the pointer width of our program because
+   we may be building a fat Mach-O file containing both 32-bit and 64-bit
+   variants. However Mach-O runs a limited set of platforms so detection
+   via preprocessor is not difficult.  */
+
+#if defined(__MACH__)
+#if defined(__LP64__)
+#define BACKTRACE_BITS 64
+#else
+#define BACKTRACE_BITS 32
+#endif
+#else
+#error Attempting to build Mach-O support on incorrect platform
+#endif
+
+#if defined(__x86_64__)
+#define NATIVE_CPU_TYPE CPU_TYPE_X86_64
+#elif defined(__i386__)
+#define NATIVE_CPU_TYPE CPU_TYPE_X86
+#elif defined(__aarch64__)
+#define NATIVE_CPU_TYPE CPU_TYPE_ARM64
+#elif defined(__arm__)
+#define NATIVE_CPU_TYPE CPU_TYPE_ARM
+#else
+#error Could not detect native Mach-O cpu_type_t
+#endif
+
+#include <sys/types.h>
+#include <sys/syslimits.h>
+#include <string.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+#include <mach-o/fat.h>
+#include <mach-o/dyld.h>
+#include <uuid/uuid.h>
+#include <dirent.h>
+#include <stdlib.h>
+
+#include "backtrace.h"
+#include "internal.h"
+
+struct macho_commands_view
+{
+    struct backtrace_view view;
+    uint32_t commands_count;
+    uint32_t commands_total_size;
+    int bytes_swapped;
+    size_t base_offset;
+};
+
+enum debug_section
+{
+    DEBUG_INFO,
+    DEBUG_LINE,
+    DEBUG_ABBREV,
+    DEBUG_RANGES,
+    DEBUG_STR,
+    DEBUG_MAX
+};
+
+static const char *const debug_section_names[DEBUG_MAX] =
+    {
+        "__debug_info",
+        "__debug_line",
+        "__debug_abbrev",
+        "__debug_ranges",
+        "__debug_str"
+    };
+
+struct found_dwarf_section
+{
+    uint32_t file_offset;
+    uintptr_t file_size;
+    const unsigned char *data;
+};
+
+/* Mach-O symbols don't have a length. As a result we have to infer it
+   by sorting the symbol addresses for each image and recording the
+   memory range attributed to each image.  */
+struct macho_symbol
+{
+    uintptr_t addr;
+    size_t size;
+    const char *name;
+};
+
+struct macho_syminfo_data
+{
+    struct macho_syminfo_data *next;
+    struct macho_symbol *symbols;
+    size_t symbol_count;
+    uintptr_t min_addr;
+    uintptr_t max_addr;
+};
+
+uint16_t
+macho_file_to_host_u16 (int file_bytes_swapped, uint16_t input)
+{
+  if (file_bytes_swapped)
+    return (input >> 8) | (input << 8);
+  else
+    return input;
+}
+
+uint32_t
+macho_file_to_host_u32 (int file_bytes_swapped, uint32_t input)
+{
+  if (file_bytes_swapped)
+    {
+      return ((input >> 24) & 0x000000FF)
+             | ((input >> 8) & 0x0000FF00)
+             | ((input << 8) & 0x00FF0000)
+             | ((input << 24) & 0xFF000000);
+    }
+  else
+    {
+      return input;
+    }
+}
+
+uint64_t
+macho_file_to_host_u64 (int file_bytes_swapped, uint64_t input)
+{
+  if (file_bytes_swapped)
+    {
+      return macho_file_to_host_u32 (file_bytes_swapped,
+                                     (uint32_t) (input >> 32))
+             | (((uint64_t) macho_file_to_host_u32 (file_bytes_swapped,
+                                                    (uint32_t) input)) << 32);
+    }
+  else
+    {
+      return input;
+    }
+}
+
+#if BACKTRACE_BITS == 64
+#define macho_file_to_host_usize macho_file_to_host_u64
+typedef struct mach_header_64 mach_header_native_t;
+#define LC_SEGMENT_NATIVE LC_SEGMENT_64
+typedef struct segment_command_64 segment_command_native_t;
+typedef struct nlist_64 nlist_native_t;
+typedef struct section_64 section_native_t;
+#else /* BACKTRACE_BITS == 32 */
+#define macho_file_to_host_usize macho_file_to_host_u32
+typedef struct mach_header mach_header_native_t;
+#define LC_SEGMENT_NATIVE LC_SEGMENT
+typedef struct segment_command segment_command_native_t;
+typedef struct nlist nlist_native_t;
+typedef struct section section_native_t;
+#endif
+
+// Gets a view into a Mach-O image, taking any slice offset into account
+int
+macho_get_view (struct backtrace_state *state, int descriptor,
+                off_t offset, size_t size,
+                backtrace_error_callback error_callback,
+                void *data, struct macho_commands_view *commands_view,
+                struct backtrace_view *view)
+{
+  return backtrace_get_view (state, descriptor,
+                             commands_view->base_offset + offset, size,
+                             error_callback, data, view);
+}
+
+int
+macho_get_commands (struct backtrace_state *state, int descriptor,
+                    backtrace_error_callback error_callback,
+                    void *data, struct macho_commands_view *commands_view,
+                    int *incompatible)
+{
+  int ret = 0;
+  int is_fat = 0;
+  struct backtrace_view file_header_view;
+  int file_header_view_valid = 0;
+  struct backtrace_view fat_archs_view;
+  int fat_archs_view_valid = 0;
+  const mach_header_native_t *file_header;
+  uint64_t commands_offset;
+
+  *incompatible = 0;
+
+  if (!backtrace_get_view (state, descriptor, 0, sizeof (mach_header_native_t),
+                           error_callback, data, &file_header_view))
+    goto end;
+  file_header_view_valid = 1;
+
+  switch (*(uint32_t *) file_header_view.data)
+    {
+      case MH_MAGIC:
+        if (BACKTRACE_BITS == 32)
+          commands_view->bytes_swapped = 0;
+        else
+          {
+            *incompatible = 1;
+            goto end;
+          }
+      break;
+      case MH_CIGAM:
+        if (BACKTRACE_BITS == 32)
+          commands_view->bytes_swapped = 1;
+        else
+          {
+            *incompatible = 1;
+            goto end;
+          }
+      break;
+      case MH_MAGIC_64:
+        if (BACKTRACE_BITS == 64)
+          commands_view->bytes_swapped = 0;
+        else
+          {
+            *incompatible = 1;
+            goto end;
+          }
+      break;
+      case MH_CIGAM_64:
+        if (BACKTRACE_BITS == 64)
+          commands_view->bytes_swapped = 1;
+        else
+          {
+            *incompatible = 1;
+            goto end;
+          }
+      break;
+      case FAT_MAGIC:
+        is_fat = 1;
+        commands_view->bytes_swapped = 0;
+      break;
+      case FAT_CIGAM:
+        is_fat = 1;
+        commands_view->bytes_swapped = 1;
+      break;
+      default:
+        goto end;
+    }
+
+  if (is_fat)
+    {
+      uint32_t native_slice_offset;
+      size_t archs_total_size;
+      uint32_t arch_count;
+      const struct fat_header *fat_header;
+      const struct fat_arch *archs;
+      uint32_t i;
+
+      fat_header = file_header_view.data;
+      arch_count =
+          macho_file_to_host_u32 (commands_view->bytes_swapped,
+                                  fat_header->nfat_arch);
+
+      archs_total_size = arch_count * sizeof (struct fat_arch);
+
+      if (!backtrace_get_view (state, descriptor, sizeof (struct fat_header),
+                               archs_total_size, error_callback,
+                               data, &fat_archs_view))
+        goto end;
+      fat_archs_view_valid = 1;
+
+      native_slice_offset = 0;
+      archs = fat_archs_view.data;
+      for (i = 0; i < arch_count; i++)
+        {
+          const struct fat_arch *raw_arch = archs + i;
+          int cpu_type =
+              (int) macho_file_to_host_u32 (commands_view->bytes_swapped,
+                                            (uint32_t) raw_arch->cputype);
+
+          if (cpu_type == NATIVE_CPU_TYPE)
+            {
+              native_slice_offset =
+                  macho_file_to_host_u32 (commands_view->bytes_swapped,
+                                          raw_arch->offset);
+
+              break;
+            }
+        }
+
+      if (native_slice_offset == 0)
+        {
+          *incompatible = 1;
+          goto end;
+        }
+
+      backtrace_release_view (state, &file_header_view, error_callback, data);
+      file_header_view_valid = 0;
+      if (!backtrace_get_view (state, descriptor, native_slice_offset,
+                               sizeof (mach_header_native_t), error_callback,
+                               data, &file_header_view))
+        goto end;
+      file_header_view_valid = 1;
+
+      // The endianess of the slice may be different than the fat image
+      switch (*(uint32_t *) file_header_view.data)
+        {
+          case MH_MAGIC:
+            if (BACKTRACE_BITS == 32)
+              commands_view->bytes_swapped = 0;
+            else
+              goto end;
+          break;
+          case MH_CIGAM:
+            if (BACKTRACE_BITS == 32)
+              commands_view->bytes_swapped = 1;
+            else
+              goto end;
+          break;
+          case MH_MAGIC_64:
+            if (BACKTRACE_BITS == 64)
+              commands_view->bytes_swapped = 0;
+            else
+              goto end;
+          break;
+          case MH_CIGAM_64:
+            if (BACKTRACE_BITS == 64)
+              commands_view->bytes_swapped = 1;
+            else
+              goto end;
+          break;
+          default:
+            goto end;
+        }
+
+      commands_view->base_offset = native_slice_offset;
+    }
+  else
+    commands_view->base_offset = 0;
+
+  file_header = file_header_view.data;
+  commands_view->commands_count =
+      macho_file_to_host_u32 (commands_view->bytes_swapped,
+                              file_header->ncmds);
+  commands_view->commands_total_size =
+      macho_file_to_host_u32 (commands_view->bytes_swapped,
+                              file_header->sizeofcmds);
+  commands_offset =
+      commands_view->base_offset + sizeof (mach_header_native_t);
+
+  if (!backtrace_get_view (state, descriptor, commands_offset,
+                           commands_view->commands_total_size, error_callback,
+                           data, &commands_view->view))
+    goto end;
+
+  ret = 1;
+
+end:
+  if (file_header_view_valid)
+    backtrace_release_view (state, &file_header_view, error_callback, data);
+  if (fat_archs_view_valid)
+    backtrace_release_view (state, &fat_archs_view, error_callback, data);
+  return ret;
+}
+
+int
+macho_get_uuid (struct backtrace_state *state ATTRIBUTE_UNUSED,
+                int descriptor ATTRIBUTE_UNUSED,
+                backtrace_error_callback error_callback,
+                void *data, struct macho_commands_view *commands_view,
+                uuid_t *uuid)
+{
+  size_t offset = 0;
+  uint32_t i = 0;
+
+  for (i = 0; i < commands_view->commands_count; i++)
+    {
+      const struct load_command *raw_command;
+      struct load_command command;
+
+      if (offset + sizeof (struct load_command)
+          > commands_view->commands_total_size)
+        {
+          error_callback (data,
+                          "executable file contains out of range command offset",
+                          0);
+          return 0;
+        }
+
+      raw_command =
+          commands_view->view.data + offset;
+      command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped,
+                                            raw_command->cmd);
+      command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped,
+                                                raw_command->cmdsize);
+
+      if (command.cmd == LC_UUID)
+        {
+          const struct uuid_command *uuid_command;
+
+          if (offset + sizeof (struct uuid_command)
+              > commands_view->commands_total_size)
+            {
+              error_callback (data,
+                              "executable file contains out of range command offset",
+                              0);
+              return 0;
+            }
+
+          uuid_command =
+              (struct uuid_command *) raw_command;
+          memcpy (uuid, uuid_command->uuid, sizeof (uuid_t));
+          return 1;
+        }
+
+      offset += command.cmdsize;
+    }
+
+  error_callback (data, "executable file is missing an identifying UUID", 0);
+  return 0;
+}
+
+/* Returns the base address of a Mach-O image, as encoded in the file header.
+ * WARNING: This does not take ASLR into account, which is ubiquitous on recent
+ * Darwin platforms.
+ */
+int
+macho_get_addr_range (struct backtrace_state *state ATTRIBUTE_UNUSED,
+                      int descriptor ATTRIBUTE_UNUSED,
+                      backtrace_error_callback error_callback,
+                      void *data, struct macho_commands_view *commands_view,
+                      uintptr_t *base_address, uintptr_t *max_address)
+{
+  size_t offset = 0;
+  int found_text = 0;
+  uint32_t i = 0;
+
+  *max_address = 0;
+
+  for (i = 0; i < commands_view->commands_count; i++)
+    {
+      const struct load_command *raw_command;
+      struct load_command command;
+
+      if (offset + sizeof (struct load_command)
+          > commands_view->commands_total_size)
+        {
+          error_callback (data,
+                          "executable file contains out of range command offset",
+                          0);
+          return 0;
+        }
+
+      raw_command = commands_view->view.data + offset;
+      command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped,
+                                            raw_command->cmd);
+      command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped,
+                                                raw_command->cmdsize);
+
+      if (command.cmd == LC_SEGMENT_NATIVE)
+        {
+          const segment_command_native_t *raw_segment;
+          uintptr_t segment_vmaddr;
+          uintptr_t segment_vmsize;
+          uintptr_t segment_maxaddr;
+          uintptr_t text_fileoff;
+
+          if (offset + sizeof (segment_command_native_t)
+              > commands_view->commands_total_size)
+            {
+              error_callback (data,
+                              "executable file contains out of range command offset",
+                              0);
+              return 0;
+            }
+
+          raw_segment = (segment_command_native_t *) raw_command;
+
+          segment_vmaddr = macho_file_to_host_usize (
+              commands_view->bytes_swapped, raw_segment->vmaddr);
+          segment_vmsize = macho_file_to_host_usize (
+              commands_view->bytes_swapped, raw_segment->vmsize);
+          segment_maxaddr = segment_vmaddr + segment_vmsize;
+
+          if (strncmp (raw_segment->segname, "__TEXT",
+                       sizeof (raw_segment->segname)) == 0)
+            {
+              text_fileoff = macho_file_to_host_usize (
+                  commands_view->bytes_swapped, raw_segment->fileoff);
+              *base_address = segment_vmaddr - text_fileoff;
+
+              found_text = 1;
+            }
+
+          if (segment_maxaddr > *max_address)
+            *max_address = segment_maxaddr;
+        }
+
+      offset += command.cmdsize;
+    }
+
+  if (found_text)
+    return 1;
+  else
+    {
+      error_callback (data, "executable is missing __TEXT segment", 0);
+      return 0;
+    }
+}
+
+static int
+macho_symbol_compare_addr (const void *left_raw, const void *right_raw)
+{
+  const struct macho_symbol *left = left_raw;
+  const struct macho_symbol *right = right_raw;
+
+  if (left->addr > right->addr)
+    return 1;
+  else if (left->addr < right->addr)
+    return -1;
+  else
+    return 0;
+}
+
+int
+macho_symbol_type_relevant (uint8_t type)
+{
+  uint8_t type_field = (uint8_t) (type & N_TYPE);
+
+  return !(type & N_EXT) &&
+         (type_field == N_ABS || type_field == N_SECT);
+}
+
+int
+macho_add_symtab (struct backtrace_state *state,
+                  backtrace_error_callback error_callback,
+                  void *data, int descriptor,
+                  struct macho_commands_view *commands_view,
+                  uintptr_t base_address, uintptr_t max_image_address,
+                  intptr_t vmslide, int *found_sym)
+{
+  struct macho_syminfo_data *syminfo_data;
+
+  int ret = 0;
+  size_t offset = 0;
+  struct backtrace_view symtab_view;
+  int symtab_view_valid = 0;
+  struct backtrace_view strtab_view;
+  int strtab_view_valid = 0;
+  size_t syminfo_index = 0;
+  size_t function_count = 0;
+  uint32_t i = 0;
+  uint32_t j = 0;
+  uint32_t symtab_index = 0;
+
+  *found_sym = 0;
+
+  for (i = 0; i < commands_view->commands_count; i++)
+    {
+      const struct load_command *raw_command;
+      struct load_command command;
+
+      if (offset + sizeof (struct load_command)
+          > commands_view->commands_total_size)
+        {
+          error_callback (data,
+                          "executable file contains out of range command offset",
+                          0);
+          return 0;
+        }
+
+      raw_command = commands_view->view.data + offset;
+      command.cmd = macho_file_to_host_u32 (commands_view->bytes_swapped,
+                                            raw_command->cmd);
+      command.cmdsize = macho_file_to_host_u32 (commands_view->bytes_swapped,
+                                                raw_command->cmdsize);
+
+      if (command.cmd == LC_SYMTAB)
+        {
+          const struct symtab_command *symtab_command;
+          uint32_t symbol_table_offset;
+          uint32_t symbol_count;
+          uint32_t string_table_offset;
+          uint32_t string_table_size;
+
+          if (offset + sizeof (struct symtab_command)
+              > commands_view->commands_total_size)
+            {
+              error_callback (data,
+                              "executable file contains out of range command offset",
+                              0);
+              return 0;
+            }
+
+          symtab_command = (struct symtab_command *) raw_command;
+
+          symbol_table_offset = macho_file_to_host_u32 (
+              commands_view->bytes_swapped, symtab_command->symoff);
+          symbol_count = macho_file_to_host_u32 (
+              commands_view->bytes_swapped, symtab_command->nsyms);
+          string_table_offset = macho_file_to_host_u32 (
+              commands_view->bytes_swapped, symtab_command->stroff);
+          string_table_size = macho_file_to_host_u32 (
+              commands_view->bytes_swapped, symtab_command->strsize);
+
+
+          if (!macho_get_view (state, descriptor, symbol_table_offset,
+                               symbol_count * sizeof (nlist_native_t),
+                               error_callback, data, commands_view,
+                               &symtab_view))
+            goto end;
+          symtab_view_valid = 1;
+
+          if (!macho_get_view (state, descriptor, string_table_offset,
+                               string_table_size, error_callback, data,
+                               commands_view, &strtab_view))
+            goto end;
+          strtab_view_valid = 1;
+
+          // Count functions first
+          for (j = 0; j < symbol_count; j++)
+            {
+              const nlist_native_t *raw_sym =
+                  ((const nlist_native_t *) symtab_view.data) + j;
+
+              if (macho_symbol_type_relevant (raw_sym->n_type))
+                {
+                  function_count += 1;
+                }
+            }
+
+          // Allocate space for the:
+          //  (a) macho_syminfo_data for this image
+          //  (b) macho_symbol entries
+          syminfo_data =
+              backtrace_alloc (state,
+                               sizeof (struct macho_syminfo_data),
+                               error_callback, data);
+          if (syminfo_data == NULL)
+            goto end;
+
+          syminfo_data->symbols = backtrace_alloc (
+              state, function_count * sizeof (struct macho_symbol),
+              error_callback, data);
+          if (syminfo_data->symbols == NULL)
+            goto end;
+
+          syminfo_data->symbol_count = function_count;
+          syminfo_data->next = NULL;
+          syminfo_data->min_addr = base_address;
+          syminfo_data->max_addr = max_image_address;
+
+          for (symtab_index = 0;
+               symtab_index < symbol_count; symtab_index++)
+            {
+              const nlist_native_t *raw_sym =
+                  ((const nlist_native_t *) symtab_view.data) +
+                  symtab_index;
+
+              if (macho_symbol_type_relevant (raw_sym->n_type))
+                {
+                  size_t strtab_index;
+                  const char *name;
+                  size_t max_len_plus_one;
+
+                  syminfo_data->symbols[syminfo_index].addr =
+                      macho_file_to_host_usize (commands_view->bytes_swapped,
+                                                raw_sym->n_value) + vmslide;
+
+                  strtab_index = macho_file_to_host_u32 (
+                      commands_view->bytes_swapped,
+                      raw_sym->n_un.n_strx);
+
+                  // Check the range of the supposed "string" we've been
+                  // given
+                  if (strtab_index >= string_table_size)
+                    {
+                      error_callback (
+                          data,
+                          "dSYM file contains out of range string table index",
+                          0);
+                      goto end;
+                    }
+
+                  name = strtab_view.data + strtab_index;
+                  max_len_plus_one = string_table_size - strtab_index;
+
+                  if (strnlen (name, max_len_plus_one) >= max_len_plus_one)
+                    {
+                      error_callback (
+                          data,
+                          "dSYM file contains unterminated string",
+                          0);
+                      goto end;
+                    }
+
+                  // Remove underscore prefixes
+                  if (name[0] == '_')
+                    {
+                      name = name + 1;
+                    }
+
+                  syminfo_data->symbols[syminfo_index].name = name;
+
+                  syminfo_index += 1;
+                }
+            }
+
+          backtrace_qsort (syminfo_data->symbols,
+                           syminfo_data->symbol_count,
+                           sizeof (struct macho_symbol),
+                           macho_symbol_compare_addr);
+
+          // Calculate symbol sizes
+          for (syminfo_index = 0;
+               syminfo_index < syminfo_data->symbol_count; syminfo_index++)
+            {
+              if (syminfo_index + 1 < syminfo_data->symbol_count)
+                {
+                  syminfo_data->symbols[syminfo_index].size =
+                      syminfo_data->symbols[syminfo_index + 1].addr -
+                      syminfo_data->symbols[syminfo_index].addr;
+                }
+              else
+                {
+                  syminfo_data->symbols[syminfo_index].size =
+                      max_image_address -
+                      syminfo_data->symbols[syminfo_index].addr;
+                }
+            }
+
+          if (!state->threaded)
+            {
+              struct macho_syminfo_data **pp;
+
+              for (pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
+                   *pp != NULL;
+                   pp = &(*pp)->next);
+              *pp = syminfo_data;
+            }
+          else
+            {
+              while (1)
+                {
+                  struct macho_syminfo_data **pp;
+
+                  pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
+
+                  while (1)
+                    {
+                      struct macho_syminfo_data *p;
+
+                      p = backtrace_atomic_load_pointer (pp);
+
+                      if (p == NULL)
+                        break;
+
+                      pp = &p->next;
+                    }
+
+                  if (__sync_bool_compare_and_swap (pp, NULL, syminfo_data))
+                    break;
+                }
+            }
+
+          strtab_view_valid = 0; // We need to keep string table around
+          *found_sym = 1;
+          ret = 1;
+          goto end;
+        }
+
+      offset += command.cmdsize;
+    }
+
+  // No symbol table here
+  ret = 1;
+  goto end;
+
+end:
+  if (symtab_view_valid)
+    backtrace_release_view (state, &symtab_view, error_callback, data);
+  if (strtab_view_valid)
+    backtrace_release_view (state, &strtab_view, error_callback, data);
+  return ret;
+}
+
+int
+macho_try_dwarf (struct backtrace_state *state,
+                 backtrace_error_callback error_callback,
+                 void *data, fileline *fileline_fn, uuid_t *executable_uuid,
+                 uintptr_t base_address, uintptr_t max_image_address,
+                 intptr_t vmslide, char *dwarf_filename, int *matched,
+                 int *found_sym, int *found_dwarf)
+{
+  uuid_t dwarf_uuid;
+
+  int ret = 0;
+  int dwarf_descriptor;
+  int dwarf_descriptor_valid = 0;
+  struct macho_commands_view commands_view;
+  int commands_view_valid = 0;
+  struct backtrace_view dwarf_view;
+  int dwarf_view_valid = 0;
+  size_t offset = 0;
+  struct found_dwarf_section dwarf_sections[DEBUG_MAX];
+  uintptr_t min_dwarf_offset = 0;
+  uintptr_t max_dwarf_offset = 0;
+  uint32_t i = 0;
+  uint32_t j = 0;
+  int k = 0;
+
+  *matched = 0;
+  *found_sym = 0;
+  *found_dwarf = 0;
+
+  if ((dwarf_descriptor = backtrace_open (dwarf_filename, error_callback,
+                                          data, NULL)) == 0)
+    goto end;
+  dwarf_descriptor_valid = 1;
+
+  int incompatible;
+  if (!macho_get_commands (state, dwarf_descriptor, error_callback, data,
+                           &commands_view, &incompatible))
+    {
+      // Failing to read the header here is fine, because this dSYM may be
+      // for a different architecture
+      if (incompatible)
+        {
+          ret = 1;
+        }
+      goto end;
+    }
+  commands_view_valid = 1;
+
+  // Get dSYM UUID and compare
+  if (!macho_get_uuid (state, dwarf_descriptor, error_callback, data,
+                       &commands_view, &dwarf_uuid))
+    {
+      error_callback (data, "dSYM file is missing an identifying uuid", 0);
+      goto end;
+    }
+  if (memcmp (executable_uuid, &dwarf_uuid, sizeof (uuid_t)) != 0)
+    {
+      // DWARF doesn't belong to desired executable
+      ret = 1;
+      goto end;
+    }
+
+  *matched = 1;
+
+  // Read symbol table
+  if (!macho_add_symtab (state, error_callback, data, dwarf_descriptor,
+                         &commands_view, base_address, max_image_address,
+                         vmslide, found_sym))
+    goto end;
+
+  // Get DWARF sections
+
+  memset (dwarf_sections, 0, sizeof (dwarf_sections));
+  offset = 0;
+  for (i = 0; i < commands_view.commands_count; i++)
+    {
+      const struct load_command *raw_command;
+      struct load_command command;
+
+      if (offset + sizeof (struct load_command)
+          > commands_view.commands_total_size)
+        {
+          error_callback (data,
+                          "dSYM file contains out of range command offset", 0);
+          goto end;
+        }
+
+      raw_command = commands_view.view.data + offset;
+      command.cmd = macho_file_to_host_u32 (commands_view.bytes_swapped,
+                                            raw_command->cmd);
+      command.cmdsize = macho_file_to_host_u32 (commands_view.bytes_swapped,
+                                                raw_command->cmdsize);
+
+      if (command.cmd == LC_SEGMENT_NATIVE)
+        {
+          uint32_t section_count;
+          size_t section_offset;
+          const segment_command_native_t *raw_segment;
+
+          if (offset + sizeof (segment_command_native_t)
+              > commands_view.commands_total_size)
+            {
+              error_callback (data,
+                              "dSYM file contains out of range command offset",
+                              0);
+              goto end;
+            }
+
+          raw_segment = (const segment_command_native_t *) raw_command;
+
+          if (strncmp (raw_segment->segname, "__DWARF",
+                       sizeof (raw_segment->segname)) == 0)
+            {
+              section_count = macho_file_to_host_u32 (
+                  commands_view.bytes_swapped,
+                  raw_segment->nsects);
+
+              section_offset = offset + sizeof (segment_command_native_t);
+
+              // Search sections for relevant DWARF section names
+              for (j = 0; j < section_count; j++)
+                {
+                  const section_native_t *raw_section;
+
+                  if (section_offset + sizeof (section_native_t) >
+                      commands_view.commands_total_size)
+                    {
+                      error_callback (data,
+                                      "dSYM file contains out of range command offset",
+                                      0);
+                      goto end;
+                    }
+
+                  raw_section = commands_view.view.data + section_offset;
+
+                  for (k = 0; k < DEBUG_MAX; k++)
+                    {
+                      uintptr_t dwarf_section_end;
+
+                      if (strncmp (raw_section->sectname,
+                                   debug_section_names[k],
+                                   sizeof (raw_section->sectname)) == 0)
+                        {
+                          *found_dwarf = 1;
+
+                          dwarf_sections[k].file_offset =
+                              macho_file_to_host_u32 (
+                                  commands_view.bytes_swapped,
+                                  raw_section->offset);
+                          dwarf_sections[k].file_size =
+                              macho_file_to_host_usize (
+                                  commands_view.bytes_swapped,
+                                  raw_section->size);
+
+                          if (min_dwarf_offset == 0 ||
+                              dwarf_sections[k].file_offset <
+                              min_dwarf_offset)
+                            min_dwarf_offset = dwarf_sections[k].file_offset;
+
+                          dwarf_section_end =
+                              dwarf_sections[k].file_offset +
+                              dwarf_sections[k].file_size;
+                          if (dwarf_section_end > max_dwarf_offset)
+                            max_dwarf_offset = dwarf_section_end;
+
+                          break;
+                        }
+                    }
+
+                  section_offset += sizeof (section_native_t);
+                }
+
+              break;
+            }
+        }
+
+      offset += command.cmdsize;
+    }
+
+  if (!*found_dwarf)
+    {
+      // No DWARF in this file
+      ret = 1;
+      goto end;
+    }
+
+  if (!macho_get_view (state, dwarf_descriptor, (off_t) min_dwarf_offset,
+                       max_dwarf_offset - min_dwarf_offset, error_callback,
+                       data, &commands_view, &dwarf_view))
+    goto end;
+  dwarf_view_valid = 1;
+
+  for (i = 0; i < DEBUG_MAX; i++)
+    {
+      if (dwarf_sections[i].file_offset == 0)
+        dwarf_sections[i].data = NULL;
+      else
+        dwarf_sections[i].data =
+            dwarf_view.data + dwarf_sections[i].file_offset - min_dwarf_offset;
+    }
+
+  if (!backtrace_dwarf_add (state, vmslide,
+                            dwarf_sections[DEBUG_INFO].data,
+                            dwarf_sections[DEBUG_INFO].file_size,
+                            dwarf_sections[DEBUG_LINE].data,
+                            dwarf_sections[DEBUG_LINE].file_size,
+                            dwarf_sections[DEBUG_ABBREV].data,
+                            dwarf_sections[DEBUG_ABBREV].file_size,
+                            dwarf_sections[DEBUG_RANGES].data,
+                            dwarf_sections[DEBUG_RANGES].file_size,
+                            dwarf_sections[DEBUG_STR].data,
+                            dwarf_sections[DEBUG_STR].file_size,
+                            ((__DARWIN_BYTE_ORDER == __DARWIN_BIG_ENDIAN)
+                            ^ commands_view.bytes_swapped),
+                            error_callback, data, fileline_fn))
+    goto end;
+
+  // Don't release the DWARF view because it is still in use
+  dwarf_descriptor_valid = 0;
+  dwarf_view_valid = 0;
+  ret = 1;
+
+end:
+  if (dwarf_descriptor_valid)
+    backtrace_close (dwarf_descriptor, error_callback, data);
+  if (commands_view_valid)
+    backtrace_release_view (state, &commands_view.view, error_callback, data);
+  if (dwarf_view_valid)
+    backtrace_release_view (state, &dwarf_view, error_callback, data);
+  return ret;
+}
+
+int
+macho_try_dsym (struct backtrace_state *state,
+                backtrace_error_callback error_callback,
+                void *data, fileline *fileline_fn, uuid_t *executable_uuid,
+                uintptr_t base_address, uintptr_t max_image_address,
+                intptr_t vmslide, char *dsym_filename, int *matched,
+                int *found_sym, int *found_dwarf)
+{
+  int ret = 0;
+  char dwarf_image_dir_path[PATH_MAX];
+  DIR *dwarf_image_dir;
+  int dwarf_image_dir_valid = 0;
+  struct dirent *directory_entry;
+  char dwarf_filename[PATH_MAX];
+  int dwarf_matched;
+  int dwarf_had_sym;
+  int dwarf_had_dwarf;
+
+  *matched = 0;
+  *found_sym = 0;
+  *found_dwarf = 0;
+
+  strncpy (dwarf_image_dir_path, dsym_filename, PATH_MAX);
+  strncat (dwarf_image_dir_path, "/Contents/Resources/DWARF", PATH_MAX);
+
+  if (!(dwarf_image_dir = opendir (dwarf_image_dir_path)))
+    {
+      error_callback (data, "could not open DWARF directory in dSYM",
+                      0);
+      goto end;
+    }
+  dwarf_image_dir_valid = 1;
+
+  while ((directory_entry = readdir (dwarf_image_dir)))
+    {
+      if (directory_entry->d_type != DT_REG)
+        continue;
+
+      strncpy (dwarf_filename, dwarf_image_dir_path, PATH_MAX);
+      strncat (dwarf_filename, "/", PATH_MAX);
+      strncat (dwarf_filename, directory_entry->d_name, PATH_MAX);
+
+      if (!macho_try_dwarf (state, error_callback, data, fileline_fn,
+                            executable_uuid, base_address, max_image_address,
+                            vmslide, dwarf_filename,
+                            &dwarf_matched, &dwarf_had_sym, &dwarf_had_dwarf))
+        goto end;
+
+      if (dwarf_matched)
+        {
+          *matched = 1;
+          *found_sym = dwarf_had_sym;
+          *found_dwarf = dwarf_had_dwarf;
+          ret = 1;
+          goto end;
+        }
+    }
+
+  // No matching DWARF in this dSYM
+  ret = 1;
+  goto end;
+
+end:
+  if (dwarf_image_dir_valid)
+    closedir (dwarf_image_dir);
+  return ret;
+}
+
+int
+macho_add (struct backtrace_state *state,
+           backtrace_error_callback error_callback, void *data, int descriptor,
+           const char *filename, fileline *fileline_fn, intptr_t vmslide,
+           int *found_sym, int *found_dwarf)
+{
+  uuid_t image_uuid;
+  uintptr_t image_file_base_address;
+  uintptr_t image_file_max_address;
+  uintptr_t image_actual_base_address = 0;
+  uintptr_t image_actual_max_address = 0;
+
+  int ret = 0;
+  struct macho_commands_view commands_view;
+  int commands_view_valid = 0;
+  char executable_dirname[PATH_MAX];
+  size_t filename_len;
+  DIR *executable_dir = NULL;
+  int executable_dir_valid = 0;
+  struct dirent *directory_entry;
+  char dsym_full_path[PATH_MAX];
+  static const char *extension;
+  size_t extension_len;
+  ssize_t i;
+
+  *found_sym = 0;
+  *found_dwarf = 0;
+
+  // Find Mach-O commands list
+  int incompatible;
+  if (!macho_get_commands (state, descriptor, error_callback, data,
+                           &commands_view, &incompatible))
+    goto end;
+  commands_view_valid = 1;
+
+  // First we need to get the uuid of our file so we can hunt down the correct
+  // dSYM
+  if (!macho_get_uuid (state, descriptor, error_callback, data, &commands_view,
+                       &image_uuid))
+    goto end;
+
+  // Now we need to find the in memory base address. Step one is to find out
+  // what the executable thinks the base address is
+  if (!macho_get_addr_range (state, descriptor, error_callback, data,
+                             &commands_view,
+                             &image_file_base_address,
+                             &image_file_max_address))
+    goto end;
+
+  image_actual_base_address =
+      image_file_base_address + vmslide;
+  image_actual_max_address =
+      image_file_max_address + vmslide;
+
+  if (image_actual_base_address == 0)
+    {
+      error_callback (data, "executable file is not loaded", 0);
+      goto end;
+    }
+
+  // Look for dSYM in our executable's directory
+  strncpy (executable_dirname, filename, PATH_MAX);
+  filename_len = strlen (executable_dirname);
+  for (i = filename_len - 1; i >= 0; i--)
+    {
+      if (executable_dirname[i] == '/')
+        {
+          executable_dirname[i] = '\0';
+          break;
+        }
+      else if (i == 0)
+        {
+          executable_dirname[0] = '.';
+          executable_dirname[1] = '\0';
+          break;
+        }
+    }
+
+  if (!(executable_dir = opendir (executable_dirname)))
+    {
+      error_callback (data, "could not open directory containing executable",
+                      0);
+      goto end;
+    }
+  executable_dir_valid = 1;
+
+  extension = ".dSYM";
+  extension_len = strlen (extension);
+  while ((directory_entry = readdir (executable_dir)))
+    {
+      if (directory_entry->d_namlen < extension_len)
+        continue;
+      if (strncasecmp (directory_entry->d_name + directory_entry->d_namlen
+                       - extension_len, extension, extension_len) == 0)
+        {
+          int matched;
+          int dsym_had_sym;
+          int dsym_had_dwarf;
+
+          // Found a dSYM
+          strncpy (dsym_full_path, executable_dirname, PATH_MAX);
+          strncat (dsym_full_path, "/", PATH_MAX);
+          strncat (dsym_full_path, directory_entry->d_name, PATH_MAX);
+
+          if (!macho_try_dsym (state, error_callback, data,
+                               fileline_fn, &image_uuid,
+                               image_actual_base_address,
+                               image_actual_max_address, vmslide,
+                               dsym_full_path,
+                               &matched, &dsym_had_sym, &dsym_had_dwarf))
+            goto end;
+
+          if (matched)
+            {
+              *found_sym = dsym_had_sym;
+              *found_dwarf = dsym_had_dwarf;
+              ret = 1;
+              goto end;
+            }
+        }
+    }
+
+  // No matching dSYM
+  ret = 1;
+  goto end;
+
+end:
+  if (commands_view_valid)
+    backtrace_release_view (state, &commands_view.view, error_callback,
+                            data);
+  if (executable_dir_valid)
+    closedir (executable_dir);
+  return ret;
+}
+
+static int
+macho_symbol_search (const void *vkey, const void *ventry)
+{
+  const uintptr_t *key = (const uintptr_t *) vkey;
+  const struct macho_symbol *entry = (const struct macho_symbol *) ventry;
+  uintptr_t addr;
+
+  addr = *key;
+  if (addr < entry->addr)
+    return -1;
+  else if (addr >= entry->addr + entry->size)
+    return 1;
+  else
+    return 0;
+}
+
+static void
+macho_syminfo (struct backtrace_state *state,
+               uintptr_t addr,
+               backtrace_syminfo_callback callback,
+               backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
+               void *data)
+{
+  struct macho_syminfo_data *edata;
+  struct macho_symbol *sym = NULL;
+
+  if (!state->threaded)
+    {
+      for (edata = (struct macho_syminfo_data *) state->syminfo_data;
+           edata != NULL;
+           edata = edata->next)
+        {
+          if (addr >= edata->min_addr && addr <= edata->max_addr)
+            {
+              sym = ((struct macho_symbol *)
+                  bsearch (&addr, edata->symbols, edata->symbol_count,
+                           sizeof (struct macho_symbol), macho_symbol_search));
+              if (sym != NULL)
+                break;
+            }
+        }
+    }
+  else
+    {
+      struct macho_syminfo_data **pp;
+
+      pp = (struct macho_syminfo_data **) (void *) &state->syminfo_data;
+      while (1)
+        {
+          edata = backtrace_atomic_load_pointer (pp);
+          if (edata == NULL)
+            break;
+
+          if (addr >= edata->min_addr && addr <= edata->max_addr)
+            {
+              sym = ((struct macho_symbol *)
+                  bsearch (&addr, edata->symbols, edata->symbol_count,
+                           sizeof (struct macho_symbol), macho_symbol_search));
+              if (sym != NULL)
+                break;
+            }
+
+          pp = &edata->next;
+        }
+    }
+
+  if (sym == NULL)
+    callback (data, addr, NULL, 0, 0);
+  else
+    callback (data, addr, sym->name, sym->addr, sym->size);
+}
+
+
+static int
+macho_nodebug (struct backtrace_state *state ATTRIBUTE_UNUSED,
+               uintptr_t pc ATTRIBUTE_UNUSED,
+               backtrace_full_callback callback ATTRIBUTE_UNUSED,
+               backtrace_error_callback error_callback, void *data)
+{
+  error_callback (data, "no debug info in Mach-O executable", -1);
+  return 0;
+}
+
+static void
+macho_nosyms (struct backtrace_state *state ATTRIBUTE_UNUSED,
+              uintptr_t addr ATTRIBUTE_UNUSED,
+              backtrace_syminfo_callback callback ATTRIBUTE_UNUSED,
+              backtrace_error_callback error_callback, void *data)
+{
+  error_callback (data, "no symbol table in Mach-O executable", -1);
+}
+
+int
+backtrace_initialize (struct backtrace_state *state, int descriptor,
+                      backtrace_error_callback error_callback,
+                      void *data, fileline *fileline_fn)
+{
+  int ret;
+  fileline macho_fileline_fn = macho_nodebug;
+  int found_sym = 0;
+  int found_dwarf = 0;
+  uint32_t i = 0;
+  uint32_t loaded_image_count;
+
+  // Add all loaded images
+  loaded_image_count = _dyld_image_count ();
+  for (i = 0; i < loaded_image_count; i++)
+    {
+      int current_found_sym;
+      int current_found_dwarf;
+      int current_descriptor;
+      intptr_t current_vmslide;
+      const char *current_name;
+
+      current_vmslide = _dyld_get_image_vmaddr_slide (i);
+      current_name = _dyld_get_image_name (i);
+
+      if (current_name == NULL || (i != 0 && current_vmslide == 0))
+        continue;
+
+      if (!(current_descriptor =
+                backtrace_open (current_name, error_callback, data, NULL)))
+        {
+          continue;
+        }
+
+      if (macho_add (state, error_callback, data, current_descriptor,
+                      current_name, &macho_fileline_fn, current_vmslide,
+                      &current_found_sym, &current_found_dwarf))
+        {
+          found_sym = found_sym || current_found_sym;
+          found_dwarf = found_dwarf || current_found_dwarf;
+        }
+
+      backtrace_close (current_descriptor, error_callback, data);
+    }
+
+  if (!state->threaded)
+    {
+      if (found_sym)
+        state->syminfo_fn = macho_syminfo;
+      else if (state->syminfo_fn == NULL)
+        state->syminfo_fn = macho_nosyms;
+    }
+  else
+    {
+      if (found_sym)
+        backtrace_atomic_store_pointer (&state->syminfo_fn, macho_syminfo);
+      else
+        (void) __sync_bool_compare_and_swap (&state->syminfo_fn, NULL,
+                                             macho_nosyms);
+    }
+
+  if (!state->threaded)
+    {
+      if (state->fileline_fn == NULL || state->fileline_fn == macho_nodebug)
+        *fileline_fn = macho_fileline_fn;
+    }
+  else
+    {
+      fileline current_fn;
+
+      current_fn = backtrace_atomic_load_pointer (&state->fileline_fn);
+      if (current_fn == NULL || current_fn == macho_nodebug)
+        *fileline_fn = macho_fileline_fn;
+    }
+
+  return 1;
+}
+
index dc1f2981a50ad7406754e74f6adf0573140e0a2e..ec6525485f7a1d2a5107d4490f90ae8370936d51 100644 (file)
@@ -481,30 +481,6 @@ fn min(self, other: Self) -> Self
     where Self: Sized {
         if self <= other { self } else { other }
     }
-
-    /// Returns max if self is greater than max, and min if self is less than min.
-    /// Otherwise this will return self.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(clamp)]
-    ///
-    /// assert!((-3).clamp(-2, 1) == -2);
-    /// assert!(0.clamp(-2, 1) == 0);
-    /// assert!(2.clamp(-2, 1) == 1);
-    /// ```
-    ///
-    /// # Panics
-    /// Panics if min > max.
-    #[unstable(feature = "clamp", issue = "44095")]
-    fn clamp(self, min: Self, max: Self) -> Self
-    where Self: Sized {
-        assert!(min <= max);
-        if self < min { min }
-        else if self > max { max }
-        else { self }
-    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
index caa912c7c8bafde6fd3588d05be5f77bc40d141e..e7dd7ea1217dc9acaf2755e6ce4ab8cc6158f9eb 100644 (file)
@@ -62,7 +62,7 @@
 
 use hir::def_id::{CrateNum, DefId};
 use hir::map::DefPathHash;
-use hir::HirId;
+use hir::{HirId, ItemLocalId};
 
 use ich::Fingerprint;
 use ty::{TyCtxt, Instance, InstanceDef};
@@ -682,6 +682,25 @@ fn to_debug_str(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> String {
     }
 }
 
+impl<'a, 'gcx: 'tcx + 'a, 'tcx: 'a> DepNodeParams<'a, 'gcx, 'tcx> for (HirId,) {
+    const CAN_RECONSTRUCT_QUERY_KEY: bool = false;
+
+    // We actually would not need to specialize the implementation of this
+    // method but it's faster to combine the hashes than to instantiate a full
+    // hashing context and stable-hashing state.
+    fn to_fingerprint(&self, tcx: TyCtxt) -> Fingerprint {
+        let (HirId {
+            owner,
+            local_id: ItemLocalId(local_id),
+        },) = *self;
+
+        let def_path_hash = tcx.def_path_hash(DefId::local(owner));
+        let local_id = Fingerprint::from_smaller_hash(local_id as u64);
+
+        def_path_hash.0.combine(local_id)
+    }
+}
+
 /// A "work product" corresponds to a `.o` (or other) file that we
 /// save in between runs. These ids do not have a DefId but rather
 /// some independent path or string that persists between runs without
index e85e8e2bdb8c9c287613a2259f24dd807f2fc4c9..3fe3a3dc58560ef0481d2fd291278a6a29d817b1 100644 (file)
@@ -1160,6 +1160,18 @@ pub fn resolve_type_vars_if_possible<T>(&self, value: &T) -> T
         value.fold_with(&mut r)
     }
 
+    /// Returns true if `T` contains unresolved type variables. In the
+    /// process of visiting `T`, this will resolve (where possible)
+    /// type variables in `T`, but it never constructs the final,
+    /// resolved type, so it's more efficient than
+    /// `resolve_type_vars_if_possible()`.
+    pub fn any_unresolved_type_vars<T>(&self, value: &T) -> bool
+        where T: TypeFoldable<'tcx>
+    {
+        let mut r = resolve::UnresolvedTypeFinder::new(self);
+        value.visit_with(&mut r)
+    }
+
     pub fn resolve_type_and_region_vars_if_possible<T>(&self, value: &T) -> T
         where T: TypeFoldable<'tcx>
     {
index 639a330dc6e67dffdb4d7026154f3a8bd2556030..10899e42afb819b74ad124db8506ca87a939f930 100644 (file)
@@ -10,7 +10,7 @@
 
 use super::{InferCtxt, FixupError, FixupResult};
 use ty::{self, Ty, TyCtxt, TypeFoldable};
-use ty::fold::TypeFolder;
+use ty::fold::{TypeFolder, TypeVisitor};
 
 ///////////////////////////////////////////////////////////////////////////
 // OPPORTUNISTIC TYPE RESOLVER
@@ -80,6 +80,43 @@ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
     }
 }
 
+///////////////////////////////////////////////////////////////////////////
+// UNRESOLVED TYPE FINDER
+
+/// The unresolved type **finder** walks your type and searches for
+/// type variables that don't yet have a value. They get pushed into a
+/// vector. It does not construct the fully resolved type (which might
+/// involve some hashing and so forth).
+pub struct UnresolvedTypeFinder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
+    infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+}
+
+impl<'a, 'gcx, 'tcx> UnresolvedTypeFinder<'a, 'gcx, 'tcx> {
+    pub fn new(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>) -> Self {
+        UnresolvedTypeFinder { infcx }
+    }
+}
+
+impl<'a, 'gcx, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'gcx, 'tcx> {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> bool {
+        let t = self.infcx.shallow_resolve(t);
+        if t.has_infer_types() {
+            if let ty::TyInfer(_) = t.sty {
+                // Since we called `shallow_resolve` above, this must
+                // be an (as yet...) unresolved inference variable.
+                true
+            } else {
+                // Otherwise, visit its contents.
+                t.super_visit_with(self)
+            }
+        } else {
+            // Micro-optimize: no inference types at all Can't have unresolved type
+            // variables, no need to visit the contents.
+            false
+        }
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////
 // FULL TYPE RESOLUTION
 
index 1088ada667fbb3cb16634d84bc01083f3ca4ede5..9a0d76144368a61a082fcf90c0fe957283ac6b9d 100644 (file)
@@ -25,7 +25,7 @@
 use super::util;
 
 use hir::def_id::DefId;
-use infer::InferOk;
+use infer::{InferCtxt, InferOk};
 use infer::type_variable::TypeVariableOrigin;
 use rustc_data_structures::snapshot_map::{Snapshot, SnapshotMap};
 use syntax::ast;
@@ -416,7 +416,8 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
     // bounds. It might be the case that we want two distinct caches,
     // or else another kind of cache entry.
 
-    match infcx.projection_cache.borrow_mut().try_start(cache_key) {
+    let cache_result = infcx.projection_cache.borrow_mut().try_start(cache_key);
+    match cache_result {
         Ok(()) => { }
         Err(ProjectionCacheEntry::Ambiguous) => {
             // If we found ambiguity the last time, that generally
@@ -466,7 +467,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                                                     projection_ty);
             selcx.infcx().report_overflow_error(&obligation, false);
         }
-        Err(ProjectionCacheEntry::NormalizedTy(ty)) => {
+        Err(ProjectionCacheEntry::NormalizedTy(mut ty)) => {
             // If we find the value in the cache, then return it along
             // with the obligations that went along with it. Note
             // that, when using a fulfillment context, these
@@ -479,6 +480,21 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
             debug!("opt_normalize_projection_type: \
                     found normalized ty `{:?}`",
                    ty);
+
+            // Once we have inferred everything we need to know, we
+            // can ignore the `obligations` from that point on.
+            if !infcx.any_unresolved_type_vars(&ty.value) {
+                infcx.projection_cache.borrow_mut().complete(cache_key);
+                ty.obligations = vec![];
+            }
+
+            push_paranoid_cache_value_obligation(infcx,
+                                                 param_env,
+                                                 projection_ty,
+                                                 cause,
+                                                 depth,
+                                                 &mut ty);
+
             return Some(ty);
         }
         Err(ProjectionCacheEntry::Error) => {
@@ -527,7 +543,10 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                     obligations,
                 }
             };
-            infcx.projection_cache.borrow_mut().insert_ty(cache_key, &result);
+
+            let cache_value = prune_cache_value_obligations(infcx, &result);
+            infcx.projection_cache.borrow_mut().insert_ty(cache_key, cache_value);
+
             Some(result)
         }
         Ok(ProjectedTy::NoProgress(projected_ty)) => {
@@ -538,7 +557,7 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
                 value: projected_ty,
                 obligations: vec![]
             };
-            infcx.projection_cache.borrow_mut().insert_ty(cache_key, &result);
+            infcx.projection_cache.borrow_mut().insert_ty(cache_key, result.clone());
             Some(result)
         }
         Err(ProjectionTyError::TooManyCandidates) => {
@@ -562,6 +581,82 @@ fn opt_normalize_projection_type<'a, 'b, 'gcx, 'tcx>(
     }
 }
 
+/// If there are unresolved type variables, then we need to include
+/// any subobligations that bind them, at least until those type
+/// variables are fully resolved.
+fn prune_cache_value_obligations<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+                                                 result: &NormalizedTy<'tcx>)
+                                                 -> NormalizedTy<'tcx> {
+    if !infcx.any_unresolved_type_vars(&result.value) {
+        return NormalizedTy { value: result.value, obligations: vec![] };
+    }
+
+    let mut obligations: Vec<_> =
+        result.obligations
+              .iter()
+              .filter(|obligation| match obligation.predicate {
+                  // We found a `T: Foo<X = U>` predicate, let's check
+                  // if `U` references any unresolved type
+                  // variables. In principle, we only care if this
+                  // projection can help resolve any of the type
+                  // variables found in `result.value` -- but we just
+                  // check for any type variables here, for fear of
+                  // indirect obligations (e.g., we project to `?0`,
+                  // but we have `T: Foo<X = ?1>` and `?1: Bar<X =
+                  // ?0>`).
+                  ty::Predicate::Projection(ref data) =>
+                      !infcx.any_unresolved_type_vars(&data.ty()),
+
+                  // We are only interested in `T: Foo<X = U>` predicates, whre
+                  // `U` references one of `unresolved_type_vars`. =)
+                  _ => false,
+              })
+              .cloned()
+              .collect();
+
+    obligations.shrink_to_fit();
+
+    NormalizedTy { value: result.value, obligations }
+}
+
+/// Whenever we give back a cache result for a projection like `<T as
+/// Trait>::Item ==> X`, we *always* include the obligation to prove
+/// that `T: Trait` (we may also include some other obligations). This
+/// may or may not be necessary -- in principle, all the obligations
+/// that must be proven to show that `T: Trait` were also returned
+/// when the cache was first populated. But there are some vague concerns,
+/// and so we take the precatuionary measure of including `T: Trait` in
+/// the result:
+///
+/// Concern #1. The current setup is fragile. Perhaps someone could
+/// have failed to prove the concerns from when the cache was
+/// populated, but also not have used a snapshot, in which case the
+/// cache could remain populated even though `T: Trait` has not been
+/// shown. In this case, the "other code" is at fault -- when you
+/// project something, you are supposed to either have a snapshot or
+/// else prove all the resulting obligations -- but it's still easy to
+/// get wrong.
+///
+/// Concern #2. Even within the snapshot, if those original
+/// obligations are not yet proven, then we are able to do projections
+/// that may yet turn out to be wrong.  This *may* lead to some sort
+/// of trouble, though we don't have a concrete example of how that
+/// can occur yet.  But it seems risky at best.
+fn push_paranoid_cache_value_obligation<'a, 'gcx, 'tcx>(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
+                                                        param_env: ty::ParamEnv<'tcx>,
+                                                        projection_ty: ty::ProjectionTy<'tcx>,
+                                                        cause: ObligationCause<'tcx>,
+                                                        depth: usize,
+                                                        result: &mut NormalizedTy<'tcx>)
+{
+    let trait_ref = projection_ty.trait_ref(infcx.tcx).to_poly_trait_ref();
+    let trait_obligation = Obligation { cause,
+                                        recursion_depth: depth,
+                                        param_env,
+                                        predicate: trait_ref.to_predicate() };
+    result.obligations.push(trait_obligation);
+}
+
 /// If we are projecting `<T as Trait>::Item`, but `T: Trait` does not
 /// hold. In various error cases, we cannot generate a valid
 /// normalized projection. Therefore, we create an inference variable
@@ -1493,10 +1588,10 @@ fn try_start(&mut self, key: ProjectionCacheKey<'tcx>)
     }
 
     /// Indicates that `key` was normalized to `value`.
-    fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: &NormalizedTy<'tcx>) {
+    fn insert_ty(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTy<'tcx>) {
         debug!("ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
                key, value);
-        let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value.clone()));
+        let fresh_key = self.map.insert(key, ProjectionCacheEntry::NormalizedTy(value));
         assert!(!fresh_key, "never started projecting `{:?}`", key);
     }
 
index ef0d844be957f0569062d667770e96d540eded3c..5c29f4f24db6bf1d95cfecb6aba479df17b6e77d 100644 (file)
@@ -1017,6 +1017,10 @@ pub fn to_poly_trait_ref(&self, tcx: TyCtxt) -> PolyTraitRef<'tcx> {
         // levels.
         ty::Binder(self.0.projection_ty.trait_ref(tcx))
     }
+
+    pub fn ty(&self) -> Binder<Ty<'tcx>> {
+        Binder(self.skip_binder().ty) // preserves binding levels
+    }
 }
 
 pub trait ToPolyTraitRef<'tcx> {
index ded97275468b9170d0ae2cb45a025ac285f5d804..f891c991321c8a15ab2f9f8ce1cf267e98cc66f3 100644 (file)
@@ -204,7 +204,7 @@ fn always_deny_drop(&self) {
 
     /// Check for NEEDS_DROP (from an ADT or const fn call) and
     /// error, unless we're in a function, or the feature-gate
-    /// for globals with destructors is enabled.
+    /// for constant with destructors is enabled.
     fn deny_drop(&self) {
         self.deny_drop_with_feature_gate_override(true);
     }
@@ -214,9 +214,9 @@ fn deny_drop_with_feature_gate_override(&self, allow_gate: bool) {
             return;
         }
 
-        // Static and const fn's allow destructors, but they're feature-gated.
-        let msg = if allow_gate && self.mode != Mode::Const {
-            // Feature-gate for globals with destructors is enabled.
+        // Constants allow destructors, but they're feature-gated.
+        let msg = if allow_gate {
+            // Feature-gate for constant with destructors is enabled.
             if self.tcx.sess.features.borrow().drop_types_in_const {
                 return;
             }
@@ -236,11 +236,13 @@ fn deny_drop_with_feature_gate_override(&self, allow_gate: bool) {
         let mut err =
             struct_span_err!(self.tcx.sess, self.span, E0493, "{}", msg);
 
-        if allow_gate && self.mode != Mode::Const {
+        if allow_gate {
             help!(&mut err,
                   "in Nightly builds, add `#![feature(drop_types_in_const)]` \
                    to the crate attributes to enable");
         } else {
+            // FIXME(eddyb) this looks up `self.mir.return_ty`.
+            // We probably want the actual return type here, if at all.
             self.find_drop_implementation_method_span()
                 .map(|span| err.span_label(span, "destructor defined here"));
 
index 00050bc35782790995fae241a6807331beac4f29..61ac541e2c13998aec67606c3fe0b4264a3a6707 100644 (file)
@@ -7,6 +7,8 @@ build = "build.rs"
 [lib]
 name = "rustdoc"
 path = "lib.rs"
+# SNAP/stage0(cargo)
+doctest = false
 
 [dependencies]
 env_logger = { version = "0.4", default-features = false }
index be02d24e44151c0275edfabcbb910a542ea917cd..dd36b28bb39acd6dcf0b9b4f360aa0624bf80648 100644 (file)
 //! the AST (e.g. see all of `clean::inline`), but this is not always a
 //! non-lossy transformation. The current format of storage for where clauses
 //! for functions and such is simply a list of predicates. One example of this
-//! is that the AST predicate of:
-//!
-//!     where T: Trait<Foo=Bar>
-//!
-//! is encoded as:
-//!
-//!     where T: Trait, <T as Trait>::Foo = Bar
+//! is that the AST predicate of: `where T: Trait<Foo=Bar>` is encoded as:
+//! `where T: Trait, <T as Trait>::Foo = Bar`.
 //!
 //! This module attempts to reconstruct the original where and/or parameter
 //! bounds by special casing scenarios such as these. Fun!
index 2d14c02bf8a592ad95f3ae3eff1140fa3e8a2cd3..8d913c7552813aa185468092fd8b4ee335071eb4 100644 (file)
 //! of `fmt::Display`. Example usage:
 //!
 //! ```
-//! use rustdoc::html::markdown::Markdown;
+//! #![feature(rustc_private)]
+//!
+//! use rustdoc::html::markdown::{RenderType, Markdown};
 //!
 //! let s = "My *markdown* _text_";
-//! let html = format!("{}", Markdown(s));
+//! let html = format!("{}", Markdown(s, RenderType::Pulldown));
 //! // ... something using html
 //! ```
 
index 7dec7eb77e1b901daa914b81f054f5f93dd553a0..ebf07eb0423a09a23f70ad731a19330fe60c18bb 100644 (file)
@@ -20,7 +20,7 @@
 fn main() {
     let target = env::var("TARGET").expect("TARGET was not set");
     let host = env::var("HOST").expect("HOST was not set");
-    if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") &&
+    if cfg!(feature = "backtrace") && !target.contains("msvc") &&
         !target.contains("emscripten") && !target.contains("fuchsia") {
         let _ = build_libbacktrace(&host, &target);
     }
index 69ca77f54b44aa70b33e2bd33952f91fabb0826d..0135cd0a588cf09e530499f3e4c60b571cbf62b2 100644 (file)
@@ -1080,32 +1080,6 @@ pub fn atanh(self) -> f32 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
 
-    /// Returns max if self is greater than max, and min if self is less than min.
-    /// Otherwise this returns self.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(clamp)]
-    /// use std::f32::NAN;
-    /// assert!((-3.0f32).clamp(-2.0f32, 1.0f32) == -2.0f32);
-    /// assert!((0.0f32).clamp(-2.0f32, 1.0f32) == 0.0f32);
-    /// assert!((2.0f32).clamp(-2.0f32, 1.0f32) == 1.0f32);
-    /// assert!((NAN).clamp(-2.0f32, 1.0f32).is_nan());
-    /// ```
-    ///
-    /// # Panics
-    /// Panics if min > max, min is NaN, or max is NaN.
-    #[unstable(feature = "clamp", issue = "44095")]
-    #[inline]
-    pub fn clamp(self, min: f32, max: f32) -> f32 {
-        assert!(min <= max);
-        let mut x = self;
-        if x < min { x = min; }
-        if x > max { x = max; }
-        x
-    }
-
     /// Raw transmutation to `u32`.
     ///
     /// Converts the `f32` into its raw memory representation,
@@ -1777,22 +1751,4 @@ fn test_snan_masking() {
         assert_ne!(nan_masked & QNAN_MASK, 0);
         assert!(nan_masked_fl.is_nan());
     }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_min_greater_than_max() {
-        1.0f32.clamp(3.0, 1.0);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_min_is_nan() {
-        1.0f32.clamp(NAN, 1.0);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_max_is_nan() {
-        1.0f32.clamp(3.0, NAN);
-    }
 }
index 6ec633bfaaac1be5dcfa5f7110ddb0671db6c3a3..d73d7cd2c7bd1cf52c088a0e45d45c4e5e688d84 100644 (file)
@@ -970,32 +970,6 @@ pub fn atanh(self) -> f64 {
         0.5 * ((2.0 * self) / (1.0 - self)).ln_1p()
     }
 
-    /// Returns max if self is greater than max, and min if self is less than min.
-    /// Otherwise this returns self.
-    ///
-    /// # Examples
-    ///
-    /// ```
-    /// #![feature(clamp)]
-    /// use std::f64::NAN;
-    /// assert!((-3.0f64).clamp(-2.0f64, 1.0f64) == -2.0f64);
-    /// assert!((0.0f64).clamp(-2.0f64, 1.0f64) == 0.0f64);
-    /// assert!((2.0f64).clamp(-2.0f64, 1.0f64) == 1.0f64);
-    /// assert!((NAN).clamp(-2.0f64, 1.0f64).is_nan());
-    /// ```
-    ///
-    /// # Panics
-    /// Panics if min > max, min is NaN, or max is NaN.
-    #[unstable(feature = "clamp", issue = "44095")]
-    #[inline]
-    pub fn clamp(self, min: f64, max: f64) -> f64 {
-        assert!(min <= max);
-        let mut x = self;
-        if x < min { x = min; }
-        if x > max { x = max; }
-        x
-    }
-
     // Solaris/Illumos requires a wrapper around log, log2, and log10 functions
     // because of their non-standard behavior (e.g. log(-n) returns -Inf instead
     // of expected NaN).
@@ -1668,22 +1642,4 @@ fn test_float_bits_conv() {
         assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0);
         assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25);
     }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_min_greater_than_max() {
-        1.0f64.clamp(3.0, 1.0);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_min_is_nan() {
-        1.0f64.clamp(NAN, 1.0);
-    }
-
-    #[test]
-    #[should_panic]
-    fn test_clamp_max_is_nan() {
-        1.0f64.clamp(3.0, NAN);
-    }
 }
index 433499a90a4054f574cb4ae8cfde1063887c0e74..33bf0d68126d4c43f2ba4b24cc5cabcb102ae54c 100644 (file)
 #![feature(cfg_target_vendor)]
 #![feature(char_error_internals)]
 #![feature(char_internals)]
-#![feature(clamp)]
 #![feature(collections_range)]
 #![feature(compiler_builtins_lib)]
 #![feature(const_fn)]
index bf52da2ed4ac51035661ff7b969fc4676c3db507..b5bf20c747be6e8ad6933ca31fc0e2a0c2096570 100644 (file)
 // symbol resolvers:
 mod printing;
 
-#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "emscripten")))]
+#[cfg(not(target_os = "emscripten"))]
 pub mod gnu {
     use io;
     use fs;
     use libc::c_char;
 
+    #[cfg(not(any(target_os = "macos", target_os = "ios")))]
     pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
         Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
     }
+
+    #[cfg(any(target_os = "macos", target_os = "ios"))]
+    pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
+        use env;
+        use os::unix::ffi::OsStrExt;
+
+        let filename = env::current_exe()?;
+        let file = fs::File::open(&filename)?;
+        let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter()
+            .map(|&x| x as c_char).collect();
+        filename_cstr.push(0); // Null terminate
+        Ok((filename_cstr, file))
+    }
 }
 
 pub struct BacktraceContext;
index 05a071a79783841072bd20c7bf505e5197cf8b1b..3a3912af021ce46cba0864cbf39984291b5e14a4 100644 (file)
@@ -31,14 +31,6 @@ pub fn resolve_symname<F>(frame: Frame,
     }
 }
 
-pub fn foreach_symbol_fileline<F>(_symbol_addr: Frame,
-                                  _f: F,
-                                  _: &BacktraceContext) -> io::Result<bool>
-    where F: FnMut(&[u8], libc::c_int) -> io::Result<()>
-{
-    Ok(false)
-}
-
 #[repr(C)]
 struct Dl_info {
     dli_fname: *const libc::c_char,
index 1ae82e01100169e5cd451f317ce4eb944547e4b7..8bd2d9eccd82a73db84ee6662d4df33e2af8e192 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2014-2017 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
 //
@@ -8,15 +8,36 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub use self::imp::{foreach_symbol_fileline, resolve_symname};
+mod dladdr;
 
-#[cfg(any(target_os = "macos", target_os = "ios",
-          target_os = "emscripten"))]
-#[path = "dladdr.rs"]
-mod imp;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+use io;
 
-#[cfg(not(any(target_os = "macos", target_os = "ios",
-              target_os = "emscripten")))]
-mod imp {
-    pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+#[cfg(target_os = "emscripten")]
+pub use self::dladdr::resolve_symname;
+
+#[cfg(target_os = "emscripten")]
+pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
+where
+    F: FnMut(&[u8], ::libc::c_int) -> io::Result<()>
+{
+    Ok(false)
+}
+
+#[cfg(not(target_os = "emscripten"))]
+pub use sys_common::gnu::libbacktrace::foreach_symbol_fileline;
+
+#[cfg(not(target_os = "emscripten"))]
+pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
+where
+    F: FnOnce(Option<&str>) -> io::Result<()>
+{
+    ::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| {
+        if symname.is_some() {
+            callback(symname)
+        } else {
+            dladdr::resolve_symname(frame, callback, bc)
+        }
+    }, bc)
 }
index ccd4b91a7b7339038cbf498571c1344bb0e574a2..30241819bd51201e0c71fbefda327a979705bcf2 100644 (file)
@@ -51,7 +51,7 @@
 pub mod net;
 
 #[cfg(feature = "backtrace")]
-#[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))),
+#[cfg(any(all(unix, not(target_os = "emscripten")),
           all(windows, target_env = "gnu"),
           target_os = "redox"))]
 pub mod gnu;
index e888f917741abdd8b13987e55da7ef72ecec1758..6c2eafe040a361bf32a3d9c12eab6ca486275cfe 100644 (file)
@@ -14,6 +14,6 @@ fn drop(&mut self) {}
 }
 
 const FOO: A = A;
-//~^ ERROR: constants are not allowed to have destructors
+//~^ ERROR: destructors in constants are an unstable feature
 
 fn main() {}
index e5f10b65ceed7ef0d001130fa3ea54d01bb92428..f8fdf8c45cbdb08d1d959e74ec08b26cd6c37585 100644 (file)
@@ -16,11 +16,18 @@ impl Drop for WithDtor {
     fn drop(&mut self) {}
 }
 
-static FOO: Option<&'static WithDtor> = Some(&WithDtor);
+static PROMOTION_FAIL_S: Option<&'static WithDtor> = Some(&WithDtor);
 //~^ ERROR statics are not allowed to have destructors
 //~| ERROR borrowed value does not live long enoug
 
-static BAR: i32 = (WithDtor, 0).1;
+const PROMOTION_FAIL_C: Option<&'static WithDtor> = Some(&WithDtor);
+//~^ ERROR constants are not allowed to have destructors
+//~| ERROR borrowed value does not live long enoug
+
+static EARLY_DROP_S: i32 = (WithDtor, 0).1;
 //~^ ERROR statics are not allowed to have destructors
 
+const EARLY_DROP_C: i32 = (WithDtor, 0).1;
+//~^ ERROR constants are not allowed to have destructors
+
 fn main () {}
index b2ab25c44b82a4ece3c97ef597e11ba44037e5ce..f81352e177322ea1a3a26853735aebfd0078ac1a 100644 (file)
@@ -33,9 +33,7 @@ macro_rules! dump_and_die {
     ($($pos:expr),*) => ({
         // FIXME(#18285): we cannot include the current position because
         // the macro span takes over the last frame's file/line.
-        if cfg!(any(target_os = "macos",
-                    target_os = "ios",
-                    target_os = "android",
+        if cfg!(any(target_os = "android",
                     all(target_os = "linux", target_arch = "arm"),
                     target_os = "freebsd",
                     target_os = "dragonfly",
index 7f8a4941494a91c7a8eee2da5fdf439252fc43a8..c085ee7d46ac33cf96c877287ba467266f15fd5f 100644 (file)
 
 #![feature(drop_types_in_const)]
 
+use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+
+static DROP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
+
 struct A(i32);
 
 impl Drop for A {
-    fn drop(&mut self) {}
+    fn drop(&mut self) {
+        // update global drop count
+        DROP_COUNTER.fetch_add(1, Ordering::SeqCst);
+    }
 }
 
 static FOO: A = A(123);
+const BAR: A = A(456);
+
+impl A {
+    const BAZ: A = A(789);
+}
 
 fn main() {
-    println!("{}", &FOO.0);
+    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
+    assert_eq!(&FOO.0, &123);
+    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 0);
+    assert_eq!(BAR.0, 456);
+    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 1);
+    assert_eq!(A::BAZ.0, 789);
+    assert_eq!(DROP_COUNTER.load(Ordering::SeqCst), 2);
 }
index ea4526b70f6a8ec6933fed23f0ee24cf92e14b2d..eae871d2d4e46143207236c8c8c94c9276bad27c 100644 (file)
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(drop_types_in_const)]
+
 struct Foo {
     a: u32
 }
@@ -24,7 +26,7 @@ impl Drop for Bar {
     fn drop(&mut self) {}
 }
 
-const F : Foo = Foo { a : 0 };
+const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1;
 
 fn main() {
 }
index afcc9a240eb4e6c266a4decb0e110c8e2b80ad99..8da11fefc177afcb18a14bbe56a2e7000b6d6f7f 100644 (file)
@@ -1,11 +1,11 @@
 error[E0493]: constants are not allowed to have destructors
-  --> $DIR/E0493.rs:27:17
+  --> $DIR/E0493.rs:29:17
    |
-16 |     fn drop(&mut self) {}
+18 |     fn drop(&mut self) {}
    |     --------------------- destructor defined here
 ...
-27 | const F : Foo = Foo { a : 0 };
-   |                 ^^^^^^^^^^^^^ constants cannot have destructors
+29 | const F : Foo = (Foo { a : 0 }, Foo { a : 1 }).1;
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constants cannot have destructors
 
 error: aborting due to previous error
 
index 34c0674a251287c94cdd1a112966bcb9010c62e8..33250c48b4763b01478d780e76206484a1d5b207 160000 (submodule)
@@ -1 +1 @@
-Subproject commit 34c0674a251287c94cdd1a112966bcb9010c62e8
+Subproject commit 33250c48b4763b01478d780e76206484a1d5b207
index b4ff403041f17957f735ad750c3241a3a428b9b7..adea17e1b22231a9036a619264b72565e3a3962f 160000 (submodule)
@@ -1 +1 @@
-Subproject commit b4ff403041f17957f735ad750c3241a3a428b9b7
+Subproject commit adea17e1b22231a9036a619264b72565e3a3962f