fast_finish: true
include:
# Images used in testing PR and try-build should be run first.
- - env: IMAGE=x86_64-gnu-llvm-3.7 RUST_BACKTRACE=1
+ - env: IMAGE=x86_64-gnu-llvm-3.9 RUST_BACKTRACE=1
if: type = pull_request OR branch = auto
- env: IMAGE=dist-x86_64-linux DEPLOY=1
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
os: osx
- osx_image: xcode7
+ osx_image: xcode7.3
if: branch = auto
# macOS builders. These are placed near the beginning because they are very
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
os: osx
- osx_image: xcode8.2
+ osx_image: xcode8.3
if: branch = auto
- env: >
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
os: osx
- osx_image: xcode8.2
+ osx_image: xcode8.3
if: branch = auto
# OSX builders producing releases. These do not run the full test suite and
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
os: osx
- osx_image: xcode7
+ osx_image: xcode7.3
if: branch = auto
- env: >
NO_LLVM_ASSERTIONS=1
NO_DEBUG_ASSERTIONS=1
os: osx
- osx_image: xcode7
+ osx_image: xcode7.3
if: branch = auto
# Linux builders, remaining docker images
outside the submodule.
-It can also be more convenient during development to set `submodules = false`
-in the `config.toml` to prevent `x.py` from resetting to the original branch.
+In order to prepare your PR, you can run the build locally by doing
+`./x.py build src/tools/TOOL`. If you will be editing the sources
+there, you may wish to set `submodules = false` in the `config.toml`
+to prevent `x.py` from resetting to the original branch.
+
+#### Breaking Tools Built With The Compiler
+[breaking-tools-built-with-the-compiler]: #breaking-tools-built-with-the-compiler
+
+Rust's build system builds a number of tools that make use of the
+internals of the compiler. This includes clippy,
+[RLS](https://github.com/rust-lang-nursery/rls) and
+[rustfmt](https://github.com/rust-lang-nursery/rustfmt). If these tools
+break because of your changes, you may run into a sort of "chicken and egg"
+problem. These tools rely on the latest compiler to be built so you can't update
+them to reflect your changes to the compiler until those changes are merged into
+the compiler. At the same time, you can't get your changes merged into the compiler
+because the rust-lang/rust build won't pass until those tools build and pass their
+tests.
+
+That means that, in the default state, you can't update the compiler without first
+fixing rustfmt, rls and the other tools that the compiler builds.
+
+Luckily, a feature was [added to Rust's build](https://github.com/rust-lang/rust/pull/45243)
+to make all of this easy to handle. The idea is that you mark the tools as "broken",
+so that the rust-lang/rust build passes without trying to build them, then land the change
+in the compiler, wait for a nightly, and go update the tools that you broke. Once you're done
+and the tools are working again, you go back in the compiler and change the tools back
+from "broken".
+
+This should avoid a bunch of synchronization dances and is also much easier on contributors as
+there's no need to block on rls/rustfmt/other tools changes going upstream.
+
+Here are those same steps in detail:
+
+1. (optional) First, if it doesn't exist already, create a `config.toml` by copying
+ `config.toml.example` in the root directory of the Rust repository.
+ Set `submodules = false` in the `[build]` section. This will prevent `x.py`
+ from resetting to the original branch after you make your changes. If you
+ need to [update any submodules to their latest versions][updating-submodules],
+ see the section of this file about that for more information.
+2. (optional) Run `./x.py test src/tools/rustfmt` (substituting the submodule
+ that broke for `rustfmt`). Fix any errors in the submodule (and possibly others).
+3. (optional) Make commits for your changes and send them to upstream repositories as a PR.
+4. (optional) Maintainers of these submodules will **not** merge the PR. The PR can't be
+ merged because CI will be broken. You'll want to write a message on the PR referencing
+ your change, and how the PR should be merged once your change makes it into a nightly.
+5. Update `src/tools/toolstate.toml` to indicate that the tool in question is "broken",
+ that will disable building it on CI. See the documentation in that file for the exact
+ configuration values you can use.
+6. Commit the changes to `src/tools/toolstate.toml`, **do not update submodules in your commit**,
+ and then update the PR you have for rust-lang/rust.
+7. Wait for your PR to merge.
+8. Wait for a nightly
+9. (optional) Help land your PR on the upstream repository now that your changes are in nightly.
+10. (optional) Send a PR to rust-lang/rust updating the submodule, reverting `src/tools/toolstate.toml` back to a "building" or "testing" state.
+
+#### Updating submodules
+[updating-submodules]: #updating-submodules
+
+These instructions are specific to updating `rustfmt`, however they may apply
+to the other submodules as well. Please help by improving these instructions
+if you find any discrepencies or special cases that need to be addressed.
+
+To update the `rustfmt` submodule, start by running the appropriate
+[`git submodule` command](https://git-scm.com/book/en/v2/Git-Tools-Submodules).
+For example, to update to the latest commit on the remote master branch,
+you may want to run:
+```
+git submodule update --remote src/tools/rustfmt
+```
+If you run `./x.py build` now, and you are lucky, it may just work. If you see
+an error message about patches that did not resolve to any crates, you will need
+to complete a few more steps which are outlined with their rationale below.
+
+*(This error may change in the future to include more information.)*
+```
+error: failed to resolve patches for `https://github.com/rust-lang-nursery/rustfmt`
+
+Caused by:
+ patch for `rustfmt-nightly` in `https://github.com/rust-lang-nursery/rustfmt` did not resolve to any crates
+failed to run: ~/rust/build/x86_64-unknown-linux-gnu/stage0/bin/cargo build --manifest-path ~/rust/src/bootstrap/Cargo.toml
+```
+
+If you haven't used the `[patch]`
+section of `Cargo.toml` before, there is [some relevant documentation about it
+in the cargo docs](http://doc.crates.io/manifest.html#the-patch-section). In
+addition to that, you should read the
+[Overriding dependencies](http://doc.crates.io/specifying-dependencies.html#overriding-dependencies)
+section of the documentation as well.
+
+Specifically, the following [section in Overriding dependencies](http://doc.crates.io/specifying-dependencies.html#testing-a-bugfix) reveals what the problem is:
+
+> Next up we need to ensure that our lock file is updated to use this new version of uuid so our project uses the locally checked out copy instead of one from crates.io. The way [patch] works is that it'll load the dependency at ../path/to/uuid and then whenever crates.io is queried for versions of uuid it'll also return the local version.
+>
+> This means that the version number of the local checkout is significant and will affect whether the patch is used. Our manifest declared uuid = "1.0" which means we'll only resolve to >= 1.0.0, < 2.0.0, and Cargo's greedy resolution algorithm also means that we'll resolve to the maximum version within that range. Typically this doesn't matter as the version of the git repository will already be greater or match the maximum version published on crates.io, but it's important to keep this in mind!
+
+This says that when we updated the submodule, the version number in our
+`src/tools/rustfmt/Cargo.toml` changed. The new version is different from
+the version in `Cargo.lock`, so the build can no longer continue.
+
+To resolve this, we need to update `Cargo.lock`. Luckily, cargo provides a
+command to do this easily.
+
+First, go into the `src/` directory since that is where `Cargo.toml` is in
+the rust repository. Then run, `cargo update -p rustfmt-nightly` to solve
+the problem.
+
+```
+$ cd src
+$ cargo update -p rustfmt-nightly
+```
+
+This should change the version listed in `src/Cargo.lock` to the new version you updated
+the submodule to. Running `./x.py build` should work now.
## Writing Documentation
[writing-documentation]: #writing-documentation
## Building from Source
[building-from-source]: #building-from-source
+### Building on *nix
1. Make sure you have installed the dependencies:
* `g++` 4.7 or later or `clang++` 3.x or later
# If an external LLVM root is specified, we automatically check the version by
# default to make sure it's within the range that we're expecting, but setting
# this flag will indicate that this version check should not be done.
-#version-check = false
+#version-check = true
# Link libstdc++ statically into the librustc_llvm instead of relying on a
# dynamic version to be available.
# configure to use local rust instead of downloading a beta.
# `--local-rust-root` is optional here. If elided, we will
# use whatever rustc we find on your PATH.
-> configure --enable-rustbuild --local-rust-root=~/.cargo/ --enable-local-rebuild
+> ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild
```
After that, you can use the `--incremental` flag to actually do
incremental builds:
```
-> ../x.py build --incremental
+> ./x.py build --incremental
```
The `--incremental` flag will store incremental compilation artifacts
# option. This file may not be copied, modified, or distributed
# except according to those terms.
-from __future__ import print_function
+from __future__ import absolute_import, division, print_function
import argparse
import contextlib
import datetime
"""
config = self.get_toml(program)
if config:
- return config
+ return os.path.expanduser(config)
return os.path.join(self.bin_root(), "bin", "{}{}".format(
program, self.exe_suffix()))
if not ((module.endswith("llvm") and
self.get_toml('llvm-config')) or
(module.endswith("jemalloc") and
- self.get_toml('jemalloc')))]
+ (self.get_toml('use-jemalloc') == "false" or
+ self.get_toml('jemalloc'))))]
run(["git", "submodule", "update",
"--init", "--recursive"] + submodules,
cwd=self.rust_root, verbose=self.verbose)
"""Bootstrap tests"""
+from __future__ import absolute_import, division, print_function
import os
import doctest
import unittest
let mut config = Config::default();
config.llvm_enabled = true;
config.llvm_optimize = true;
+ config.llvm_version_check = true;
config.use_jemalloc = true;
config.backtrace = true;
config.rust_optimize = true;
# ignore-tidy-linelength
+from __future__ import absolute_import, division, print_function
import sys
import os
rust_dir = os.path.dirname(os.path.abspath(__file__))
import bootstrap
-class Option:
+class Option(object):
def __init__(self, name, rustbuild, desc, value):
self.name = name
self.rustbuild = rustbuild
let image = tmpdir(build).join(format!("{}-{}-image", name, target));
let src = build.stage_out(compiler, Mode::Libstd)
- .join(target).join("release").join("deps");
+ .join(target).join(build.cargo_dir()).join("deps");
let image_src = src.join("save-analysis");
let dst = image.join("lib/rustlib").join(target).join("analysis");
}
impl Step for Rls {
- type Output = PathBuf;
+ type Output = Option<PathBuf>;
const ONLY_BUILD_TARGETS: bool = true;
const ONLY_HOSTS: bool = true;
});
}
- fn run(self, builder: &Builder) -> PathBuf {
+ fn run(self, builder: &Builder) -> Option<PathBuf> {
let build = builder.build;
let stage = self.stage;
let target = self.target;
assert!(build.config.extended);
+ if !builder.config.toolstate.rls.testing() {
+ println!("skipping Dist RLS stage{} ({})", stage, target);
+ return None
+ }
+
println!("Dist RLS stage{} ({})", stage, target);
let src = build.src.join("src/tools/rls");
let release_num = build.release_num("rls");
.arg("--component-name=rls-preview");
build.run(&mut cmd);
- distdir(build).join(format!("{}-{}.tar.gz", name, target))
+ Some(distdir(build).join(format!("{}-{}.tar.gz", name, target)))
}
}
// upgrades rustc was upgraded before rust-std. To avoid rustc clobbering
// the std files during uninstall. To do this ensure that rustc comes
// before rust-std in the list below.
- let mut tarballs = vec![rustc_installer, cargo_installer, rls_installer,
- analysis_installer, std_installer];
+ let mut tarballs = Vec::new();
+ tarballs.push(rustc_installer);
+ tarballs.push(cargo_installer);
+ tarballs.extend(rls_installer.clone());
+ tarballs.push(analysis_installer);
+ tarballs.push(std_installer);
if build.config.docs {
tarballs.push(docs_installer);
}
}
rtf.push_str("}");
+ fn filter(contents: &str, marker: &str) -> String {
+ let start = format!("tool-{}-start", marker);
+ let end = format!("tool-{}-end", marker);
+ let mut lines = Vec::new();
+ let mut omitted = false;
+ for line in contents.lines() {
+ if line.contains(&start) {
+ omitted = true;
+ } else if line.contains(&end) {
+ omitted = false;
+ } else if !omitted {
+ lines.push(line);
+ }
+ }
+
+ lines.join("\n")
+ }
+
+ let xform = |p: &Path| {
+ let mut contents = String::new();
+ t!(t!(File::open(p)).read_to_string(&mut contents));
+ if rls_installer.is_none() {
+ contents = filter(&contents, "rls");
+ }
+ let ret = tmp.join(p.file_name().unwrap());
+ t!(t!(File::create(&ret)).write_all(contents.as_bytes()));
+ return ret
+ };
+
if target.contains("apple-darwin") {
let pkg = tmp.join("pkg");
let _ = fs::remove_dir_all(&pkg);
- t!(fs::create_dir_all(pkg.join("rustc")));
- t!(fs::create_dir_all(pkg.join("cargo")));
- t!(fs::create_dir_all(pkg.join("rust-docs")));
- t!(fs::create_dir_all(pkg.join("rust-std")));
- t!(fs::create_dir_all(pkg.join("rls")));
- t!(fs::create_dir_all(pkg.join("rust-analysis")));
-
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target)),
- &pkg.join("rustc"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target)),
- &pkg.join("cargo"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target)),
- &pkg.join("rust-docs"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target)),
- &pkg.join("rust-std"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)),
- &pkg.join("rls"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target)),
- &pkg.join("rust-analysis"));
-
- install(&etc.join("pkg/postinstall"), &pkg.join("rustc"), 0o755);
- install(&etc.join("pkg/postinstall"), &pkg.join("cargo"), 0o755);
- install(&etc.join("pkg/postinstall"), &pkg.join("rust-docs"), 0o755);
- install(&etc.join("pkg/postinstall"), &pkg.join("rust-std"), 0o755);
- install(&etc.join("pkg/postinstall"), &pkg.join("rls"), 0o755);
- install(&etc.join("pkg/postinstall"), &pkg.join("rust-analysis"), 0o755);
let pkgbuild = |component: &str| {
let mut cmd = Command::new("pkgbuild");
.arg(pkg.join(component).with_extension("pkg"));
build.run(&mut cmd);
};
- pkgbuild("rustc");
- pkgbuild("cargo");
- pkgbuild("rust-docs");
- pkgbuild("rust-std");
- pkgbuild("rls");
- pkgbuild("rust-analysis");
+
+ let prepare = |name: &str| {
+ t!(fs::create_dir_all(pkg.join(name)));
+ cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target)),
+ &pkg.join(name));
+ install(&etc.join("pkg/postinstall"), &pkg.join(name), 0o755);
+ pkgbuild(name);
+ };
+ prepare("rustc");
+ prepare("cargo");
+ prepare("rust-docs");
+ prepare("rust-std");
+ prepare("rust-analysis");
+
+ if rls_installer.is_some() {
+ prepare("rls");
+ }
// create an 'uninstall' package
install(&etc.join("pkg/postinstall"), &pkg.join("uninstall"), 0o755);
t!(t!(File::create(pkg.join("res/LICENSE.txt"))).write_all(license.as_bytes()));
install(&etc.join("gfx/rust-logo.png"), &pkg.join("res"), 0o644);
let mut cmd = Command::new("productbuild");
- cmd.arg("--distribution").arg(etc.join("pkg/Distribution.xml"))
+ cmd.arg("--distribution").arg(xform(&etc.join("pkg/Distribution.xml")))
.arg("--resources").arg(pkg.join("res"))
.arg(distdir(build).join(format!("{}-{}.pkg",
pkgname(build, "rust"),
if target.contains("windows") {
let exe = tmp.join("exe");
let _ = fs::remove_dir_all(&exe);
- t!(fs::create_dir_all(exe.join("rustc")));
- t!(fs::create_dir_all(exe.join("cargo")));
- t!(fs::create_dir_all(exe.join("rls")));
- t!(fs::create_dir_all(exe.join("rust-analysis")));
- t!(fs::create_dir_all(exe.join("rust-docs")));
- t!(fs::create_dir_all(exe.join("rust-std")));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rustc"), target))
- .join("rustc"),
- &exe.join("rustc"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "cargo"), target))
- .join("cargo"),
- &exe.join("cargo"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-docs"), target))
- .join("rust-docs"),
- &exe.join("rust-docs"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-std"), target))
- .join(format!("rust-std-{}", target)),
- &exe.join("rust-std"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rls"), target)).join("rls-preview"),
- &exe.join("rls"));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-analysis"), target))
- .join(format!("rust-analysis-{}", target)),
- &exe.join("rust-analysis"));
-
- t!(fs::remove_file(exe.join("rustc/manifest.in")));
- t!(fs::remove_file(exe.join("cargo/manifest.in")));
- t!(fs::remove_file(exe.join("rust-docs/manifest.in")));
- t!(fs::remove_file(exe.join("rust-std/manifest.in")));
- t!(fs::remove_file(exe.join("rls/manifest.in")));
- t!(fs::remove_file(exe.join("rust-analysis/manifest.in")));
+ let prepare = |name: &str| {
+ t!(fs::create_dir_all(exe.join(name)));
+ let dir = if name == "rust-std" || name == "rust-analysis" {
+ format!("{}-{}", name, target)
+ } else if name == "rls" {
+ "rls-preview".to_string()
+ } else {
+ name.to_string()
+ };
+ cp_r(&work.join(&format!("{}-{}", pkgname(build, name), target))
+ .join(dir),
+ &exe.join(name));
+ t!(fs::remove_file(exe.join(name).join("manifest.in")));
+ };
+ prepare("rustc");
+ prepare("cargo");
+ prepare("rust-analysis");
+ prepare("rust-docs");
+ prepare("rust-std");
+ if rls_installer.is_some() {
+ prepare("rls");
+ }
if target.contains("windows-gnu") {
- t!(fs::create_dir_all(exe.join("rust-mingw")));
- cp_r(&work.join(&format!("{}-{}", pkgname(build, "rust-mingw"), target))
- .join("rust-mingw"),
- &exe.join("rust-mingw"));
- t!(fs::remove_file(exe.join("rust-mingw/manifest.in")));
+ prepare("rust-mingw");
}
- install(&etc.join("exe/rust.iss"), &exe, 0o644);
+ install(&xform(&etc.join("exe/rust.iss")), &exe, 0o644);
install(&etc.join("exe/modpath.iss"), &exe, 0o644);
install(&etc.join("exe/upgrade.iss"), &exe, 0o644);
install(&etc.join("gfx/rust-logo.ico"), &exe, 0o644);
.arg("-dr").arg("Std")
.arg("-var").arg("var.StdDir")
.arg("-out").arg(exe.join("StdGroup.wxs")));
- build.run(Command::new(&heat)
- .current_dir(&exe)
- .arg("dir")
- .arg("rls")
- .args(&heat_flags)
- .arg("-cg").arg("RlsGroup")
- .arg("-dr").arg("Rls")
- .arg("-var").arg("var.RlsDir")
- .arg("-out").arg(exe.join("RlsGroup.wxs"))
- .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
+ if rls_installer.is_some() {
+ build.run(Command::new(&heat)
+ .current_dir(&exe)
+ .arg("dir")
+ .arg("rls")
+ .args(&heat_flags)
+ .arg("-cg").arg("RlsGroup")
+ .arg("-dr").arg("Rls")
+ .arg("-var").arg("var.RlsDir")
+ .arg("-out").arg(exe.join("RlsGroup.wxs"))
+ .arg("-t").arg(etc.join("msi/remove-duplicates.xsl")));
+ }
build.run(Command::new(&heat)
.current_dir(&exe)
.arg("dir")
.arg("-dDocsDir=rust-docs")
.arg("-dCargoDir=cargo")
.arg("-dStdDir=rust-std")
- .arg("-dRlsDir=rls")
.arg("-dAnalysisDir=rust-analysis")
.arg("-arch").arg(&arch)
.arg("-out").arg(&output)
.arg(&input);
add_env(build, &mut cmd, target);
+ if rls_installer.is_some() {
+ cmd.arg("-dRlsDir=rls");
+ }
if target.contains("windows-gnu") {
cmd.arg("-dGccDir=rust-mingw");
}
build.run(&mut cmd);
};
- candle(&etc.join("msi/rust.wxs"));
+ candle(&xform(&etc.join("msi/rust.wxs")));
candle(&etc.join("msi/ui.wxs"));
candle(&etc.join("msi/rustwelcomedlg.wxs"));
candle("RustcGroup.wxs".as_ref());
candle("DocsGroup.wxs".as_ref());
candle("CargoGroup.wxs".as_ref());
candle("StdGroup.wxs".as_ref());
- candle("RlsGroup.wxs".as_ref());
+ if rls_installer.is_some() {
+ candle("RlsGroup.wxs".as_ref());
+ }
candle("AnalysisGroup.wxs".as_ref());
if target.contains("windows-gnu") {
.arg("DocsGroup.wixobj")
.arg("CargoGroup.wixobj")
.arg("StdGroup.wixobj")
- .arg("RlsGroup.wixobj")
.arg("AnalysisGroup.wixobj")
.current_dir(&exe);
+ if rls_installer.is_some() {
+ cmd.arg("RlsGroup.wixobj");
+ }
+
if target.contains("windows-gnu") {
cmd.arg("GccGroup.wixobj");
}
let mut cmd = Command::new(llvm_config);
let version = output(cmd.arg("--version"));
- if version.starts_with("3.5") || version.starts_with("3.6") ||
- version.starts_with("3.7") {
- return
+ let mut parts = version.split('.').take(2)
+ .filter_map(|s| s.parse::<u32>().ok());
+ if let (Some(major), Some(minor)) = (parts.next(), parts.next()) {
+ if major > 3 || (major == 3 && minor >= 9) {
+ return
+ }
}
- panic!("\n\nbad LLVM version: {}, need >=3.5\n\n", version)
+ panic!("\n\nbad LLVM version: {}, need >=3.9\n\n", version)
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
BuildExpectation::Failing
}
}
+
+ pub fn testing(&self) -> bool {
+ match *self {
+ ToolState::Testing => true,
+ _ => false,
+ }
+ }
}
impl Default for ToolState {
COPY scripts/emscripten.sh /scripts/
RUN bash /scripts/emscripten.sh
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
ENV PATH=$PATH:/emsdk-portable
ENV PATH=$PATH:/emsdk-portable/clang/e1.37.13_64bit/
ENV PATH=$PATH:/emsdk-portable/emscripten/1.37.13/
ENV RUST_CONFIGURE_ARGS --target=$TARGETS
-ENV SCRIPT python2.7 ../x.py test --target $TARGETS
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
+ENV SCRIPT python2.7 ../x.py test --target $TARGETS src/test/run-pass
dpkg --add-architecture $APT_ARCH
apt-get update
-apt-get download \
- libc:$APT_ARCH \
+apt-get download $(apt-cache depends --recurse --no-replaces \
libc-dev:$APT_ARCH \
- libm:$APT_ARCH \
libm-dev:$APT_ARCH \
- libpthread:$APT_ARCH \
libpthread-dev:$APT_ARCH \
- libresolv:$APT_ARCH \
libresolv-dev:$APT_ARCH \
- librt:$APT_ARCH \
librt-dev:$APT_ARCH \
- libsocket:$APT_ARCH \
libsocket-dev:$APT_ARCH \
system-crt:$APT_ARCH \
- system-header:$APT_ARCH
+ system-header:$APT_ARCH \
+ | grep "^\w")
for deb in *$APT_ARCH.deb; do
dpkg -x $deb .
done
-# Strip Solaris 11 functions that are optionally used by libbacktrace.
+# Remove Solaris 11 functions that are optionally used by libbacktrace.
# This is for Solaris 10 compatibility.
-$ARCH-sun-solaris2.10-strip -N dl_iterate_phdr -N strnlen lib/$LIB_ARCH/libc.so
+rm usr/include/link.h
+patch -p0 << 'EOF'
+--- usr/include/string.h
++++ usr/include/string10.h
+@@ -93 +92,0 @@
+-extern size_t strnlen(const char *, size_t);
+EOF
mkdir /usr/local/$ARCH-sun-solaris2.10/usr
mv usr/include /usr/local/$ARCH-sun-solaris2.10/usr/include
mv usr/lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.10/lib
mv lib/$LIB_ARCH/* /usr/local/$ARCH-sun-solaris2.10/lib
-ln -s /usr/local/$ARCH-sun-solaris2.10/usr/include /usr/local/$ARCH-sun-solaris2.10/sys-include
-ln -s /usr/local/$ARCH-sun-solaris2.10/usr/include /usr/local/$ARCH-sun-solaris2.10/include
+ln -s usr/include /usr/local/$ARCH-sun-solaris2.10/sys-include
+ln -s usr/include /usr/local/$ARCH-sun-solaris2.10/include
cd ..
rm -rf solaris
--disable-libada \
--disable-libsanitizer \
--disable-libquadmath-support \
- --disable-lto \
- --with-sysroot=/usr/local/$ARCH-sun-solaris2.10
+ --disable-lto
hide_output make -j10
hide_output make install
+++ /dev/null
-FROM ubuntu:16.04
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
- g++ \
- make \
- file \
- curl \
- ca-certificates \
- python2.7 \
- git \
- cmake \
- sudo \
- gdb \
- llvm-3.7-tools \
- libedit-dev \
- zlib1g-dev \
- xz-utils
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-ENV RUST_CONFIGURE_ARGS \
- --build=x86_64-unknown-linux-gnu \
- --llvm-root=/usr/lib/llvm-3.7
-ENV RUST_CHECK_TARGET check
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ sudo \
+ gdb \
+ llvm-3.9-tools \
+ libedit-dev \
+ zlib1g-dev \
+ xz-utils
+
+COPY scripts/sccache.sh /scripts/
+RUN sh /scripts/sccache.sh
+
+# using llvm-link-shared due to libffi issues -- see #34486
+ENV RUST_CONFIGURE_ARGS \
+ --build=x86_64-unknown-linux-gnu \
+ --llvm-root=/usr/lib/llvm-3.9 \
+ --enable-llvm-link-shared
+ENV RUST_CHECK_TARGET check
$ rustdoc src/lib.rs --crate-name mycrate
```
-By default, `rustodc` assumes that the name of your crate is the same name
+By default, `rustdoc` assumes that the name of your crate is the same name
as the `.rs` file. `--crate-name` lets you override this assumption with
whatever name you choose.
-## `-L`/`--library-path`:
+## `-L`/`--library-path`: where to look for dependencies
Using this flag looks like this:
See also `--test-args`.
-## `--test-args`:
+## `--test-args`: pass options to test runner
Using this flag looks like this:
See also `--test`.
-## `--target`:
+## `--target`: generate documentation for the specified target triple
Using this flag looks like this:
```
This flag takes a list of files, and inserts them inside the `<body>` tag but
-before the other content `rustodc` would normally produce in the rendered
+before the other content `rustdoc` would normally produce in the rendered
documentation.
## `--html-after-content`: include more HTML after the content
```
This flag takes a list of files, and inserts them before the `</body>` tag but
-after the other content `rustodc` would normally produce in the rendered
+after the other content `rustdoc` would normally produce in the rendered
documentation.
flag is set in the options of the compilation target. It allows customizing the
process of resuming unwind at the end of the landing pads. The language item's name
is `eh_unwind_resume`.
+
+## List of all language items
+
+This is a list of all language items in Rust along with where they are located in
+the source code.
+
+- Primitives
+ - `i8`: `libcore/num/mod.rs`
+ - `i16`: `libcore/num/mod.rs`
+ - `i32`: `libcore/num/mod.rs`
+ - `i64`: `libcore/num/mod.rs`
+ - `i128`: `libcore/num/mod.rs`
+ - `isize`: `libcore/num/mod.rs`
+ - `u8`: `libcore/num/mod.rs`
+ - `u16`: `libcore/num/mod.rs`
+ - `u32`: `libcore/num/mod.rs`
+ - `u64`: `libcore/num/mod.rs`
+ - `u128`: `libcore/num/mod.rs`
+ - `usize`: `libcore/num/mod.rs`
+ - `f32`: `libstd/f32.rs`
+ - `f64`: `libstd/f64.rs`
+ - `char`: `libstd_unicode/char.rs`
+ - `slice`: `liballoc/slice.rs`
+ - `str`: `liballoc/str.rs`
+ - `const_ptr`: `libcore/ptr.rs`
+ - `mut_ptr`: `libcore/ptr.rs`
+ - `unsafe_cell`: `libcore/cell.rs`
+- Runtime
+ - `start`: `libstd/rt.rs`
+ - `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC)
+ - `eh_personality`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
+ - `eh_personality`: `libpanic_unwind/seh.rs` (SEH)
+ - `eh_unwind_resume`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
+ - `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC)
+ - `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH)
+ - `panic`: `libcore/panicking.rs`
+ - `panic_bounds_check`: `libcore/panicking.rs`
+ - `panic_fmt`: `libcore/panicking.rs`
+ - `panic_fmt`: `libstd/panicking.rs`
+- Allocations
+ - `owned_box`: `liballoc/boxed.rs`
+ - `exchange_malloc`: `liballoc/heap.rs`
+ - `box_free`: `liballoc/heap.rs`
+- Operands
+ - `not`: `libcore/ops/bit.rs`
+ - `bitand`: `libcore/ops/bit.rs`
+ - `bitor`: `libcore/ops/bit.rs`
+ - `bitxor`: `libcore/ops/bit.rs`
+ - `shl`: `libcore/ops/bit.rs`
+ - `shr`: `libcore/ops/bit.rs`
+ - `bitand_assign`: `libcore/ops/bit.rs`
+ - `bitor_assign`: `libcore/ops/bit.rs`
+ - `bitxor_assign`: `libcore/ops/bit.rs`
+ - `shl_assign`: `libcore/ops/bit.rs`
+ - `shr_assign`: `libcore/ops/bit.rs`
+ - `deref`: `libcore/ops/deref.rs`
+ - `deref_mut`: `libcore/ops/deref.rs`
+ - `index`: `libcore/ops/index.rs`
+ - `index_mut`: `libcore/ops/index.rs`
+ - `add`: `libcore/ops/arith.rs`
+ - `sub`: `libcore/ops/arith.rs`
+ - `mul`: `libcore/ops/arith.rs`
+ - `div`: `libcore/ops/arith.rs`
+ - `rem`: `libcore/ops/arith.rs`
+ - `neg`: `libcore/ops/arith.rs`
+ - `add_assign`: `libcore/ops/arith.rs`
+ - `sub_assign`: `libcore/ops/arith.rs`
+ - `mul_assign`: `libcore/ops/arith.rs`
+ - `div_assign`: `libcore/ops/arith.rs`
+ - `rem_assign`: `libcore/ops/arith.rs`
+ - `eq`: `libcore/cmp.rs`
+ - `ord`: `libcore/cmp.rs`
+- Functions
+ - `fn`: `libcore/ops/function.rs`
+ - `fn_mut`: `libcore/ops/function.rs`
+ - `fn_once`: `libcore/ops/function.rs`
+ - `generator_state`: `libcore/ops/generator.rs`
+ - `generator`: `libcore/ops/generator.rs`
+- Other
+ - `coerce_unsized`: `libcore/ops/unsize.rs`
+ - `drop`: `libcore/ops/drop.rs`
+ - `drop_in_place`: `libcore/ptr.rs`
+ - `clone`: `libcore/clone.rs`
+ - `copy`: `libcore/marker.rs`
+ - `send`: `libcore/marker.rs`
+ - `sized`: `libcore/marker.rs`
+ - `unsize`: `libcore/marker.rs`
+ - `sync`: `libcore/marker.rs`
+ - `phantom_data`: `libcore/marker.rs`
+ - `freeze`: `libcore/marker.rs`
+ - `debug_trait`: `libcore/fmt/mod.rs`
+ - `non_zero`: `libcore/nonzero.rs`
\ No newline at end of file
------------------------
-The compiler currently ships two default allocators: `alloc_system` and
-`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
-are normal Rust crates and contain an implementation of the routines to
-allocate and deallocate memory. The standard library is not compiled assuming
-either one, and the compiler will decide which allocator is in use at
-compile-time depending on the type of output artifact being produced.
-
-Binaries generated by the compiler will use `alloc_jemalloc` by default (where
-available). In this situation the compiler "controls the world" in the sense of
-it has power over the final link. Primarily this means that the allocator
-decision can be left up the compiler.
-
-Dynamic and static libraries, however, will use `alloc_system` by default. Here
-Rust is typically a 'guest' in another application or another world where it
-cannot authoritatively decide what allocator is in use. As a result it resorts
-back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
-memory.
-
-# Switching Allocators
-
-Although the compiler's default choices may work most of the time, it's often
-necessary to tweak certain aspects. Overriding the compiler's decision about
-which allocator is in use is done simply by linking to the desired allocator:
-
-```rust,no_run
-#![feature(alloc_system)]
-
-extern crate alloc_system;
-
-fn main() {
- let a = Box::new(4); // Allocates from the system allocator.
- println!("{}", a);
-}
-```
-
-In this example the binary generated will not link to jemalloc by default but
-instead use the system allocator. Conversely to generate a dynamic library which
-uses jemalloc by default one would write:
-
-```rust,ignore
-#![feature(alloc_jemalloc)]
-#![crate_type = "dylib"]
-
-extern crate alloc_jemalloc;
-
-pub fn foo() {
- let a = Box::new(4); // Allocates from jemalloc.
- println!("{}", a);
-}
-# fn main() {}
-```
+This feature has been replaced by [the `jemallocator` crate on crates.io.][jemallocator].
+[jemallocator]: https://crates.io/crates/jemallocator
# `alloc_system`
-The tracking issue for this feature is: [#33082]
+The tracking issue for this feature is: [#32838]
-[#33082]: https://github.com/rust-lang/rust/issues/33082
+[#32838]: https://github.com/rust-lang/rust/issues/32838
-See also [`alloc_jemalloc`](library-features/alloc-jemalloc.html).
+See also [`global_allocator`](language-features/global-allocator.html).
------------------------
Although the compiler's default choices may work most of the time, it's often
necessary to tweak certain aspects. Overriding the compiler's decision about
-which allocator is in use is done simply by linking to the desired allocator:
+which allocator is in use is done through the `#[global_allocator]` attribute:
```rust,no_run
-#![feature(alloc_system)]
+#![feature(alloc_system, global_allocator, allocator_api)]
extern crate alloc_system;
+use alloc_system::System;
+
+#[global_allocator]
+static A: System = System;
+
fn main() {
let a = Box::new(4); // Allocates from the system allocator.
println!("{}", a);
instead use the system allocator. Conversely to generate a dynamic library which
uses jemalloc by default one would write:
+(The `alloc_jemalloc` crate cannot be used to control the global allocator,
+crate.io’s `jemallocator` crate provides equivalent functionality.)
+
+```toml
+# Cargo.toml
+[dependencies]
+jemallocator = "0.1"
+```
```rust,ignore
-#![feature(alloc_jemalloc)]
+#![feature(global_allocator)]
#![crate_type = "dylib"]
-extern crate alloc_jemalloc;
+extern crate jemallocator;
+
+#[global_allocator]
+static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
pub fn foo() {
let a = Box::new(4); // Allocates from jemalloc.
}
# fn main() {}
```
-
Name: docs; Description: "HTML documentation"; Types: full
Name: cargo; Description: "Cargo, the Rust package manager"; Types: full
Name: std; Description: "The Rust Standard Library"; Types: full
+// tool-rls-start
Name: rls; Description: "RLS, the Rust Language Server"
+// tool-rls-end
[Files]
Source: "rustc/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rust
Source: "rust-docs/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: docs
Source: "cargo/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: cargo
Source: "rust-std/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: std
+// tool-rls-start
Source: "rls/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rls
Source: "rust-analysis/*.*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs; Components: rls
+// tool-rls-end
[Code]
const
<Directory Id="Docs" Name="." />
<Directory Id="Cargo" Name="." />
<Directory Id="Std" Name="." />
+ <!-- tool-rls-start -->
<Directory Id="Rls" Name="." />
<Directory Id="Analysis" Name="." />
+ <!-- tool-rls-end -->
</Directory>
</Directory>
<ComponentRef Id="PathEnvPerMachine" />
<ComponentRef Id="PathEnvPerUser" />
</Feature>
+ <!-- tool-rls-start -->
<Feature Id="RLS"
Title="RLS, the Rust Language Server"
Display="7"
<ComponentGroupRef Id="RlsGroup" />
<ComponentGroupRef Id="AnalysisGroup" />
</Feature>
+ <!-- tool-rls-end -->
<UIRef Id="RustUI" />
</Product>
<line choice="rust-std"/>
<line choice="cargo"/>
<line choice="rust-docs"/>
+ <!-- tool-rls-start -->
<line choice="rls"/>
+ <!-- tool-rls-end -->
</line>
<line choice="uninstall" />
</choices-outline>
>
<pkg-ref id="org.rust-lang.rust-docs"/>
</choice>
+ <!-- tool-rls-start -->
<choice id="rls" visible="true"
title="RLS" description="RLS, the Rust Language Server"
selected="(!choices.uninstall.selected && choices['rls'].selected) || (choices.uninstall.selected && choices.install.selected)"
<pkg-ref id="org.rust-lang.rls"/>
<pkg-ref id="org.rust-lang.rust-analysis"/>
</choice>
+ <!-- tool-rls-end -->
<pkg-ref id="org.rust-lang.rustc" version="0" onConclusion="none">rustc.pkg</pkg-ref>
<pkg-ref id="org.rust-lang.cargo" version="0" onConclusion="none">cargo.pkg</pkg-ref>
<pkg-ref id="org.rust-lang.rust-docs" version="0" onConclusion="none">rust-docs.pkg</pkg-ref>
<pkg-ref id="org.rust-lang.rust-std" version="0" onConclusion="none">rust-std.pkg</pkg-ref>
+ <!-- tool-rls-start -->
<pkg-ref id="org.rust-lang.rls" version="0" onConclusion="none">rls.pkg</pkg-ref>
+ <!-- tool-rls-end -->
<pkg-ref id="org.rust-lang.rust-analysis" version="0" onConclusion="none">rust-analysis.pkg</pkg-ref>
<pkg-ref id="org.rust-lang.uninstall" version="0" onConclusion="none">uninstall.pkg</pkg-ref>
<background file="rust-logo.png" mime-type="image/png"
/// assert_eq!(s.find("Léopard"), Some(13));
/// ```
///
- /// More complex patterns with closures:
+ /// More complex patterns using point-free style and closures:
///
/// ```
/// let s = "Löwe 老虎 Léopard";
///
/// assert_eq!(s.find(char::is_whitespace), Some(5));
/// assert_eq!(s.find(char::is_lowercase), Some(1));
+ /// assert_eq!(s.find(|c: char| c.is_whitespace() || c.is_lowercase()), Some(1));
+ /// assert_eq!(s.find(|c: char| (c < 'o') && (c > 'a')), Some(4));
/// ```
///
/// Not finding the pattern:
#![unstable(feature = "alloc_system",
reason = "this library is unlikely to be stabilized in its current \
form or name",
- issue = "27783")]
+ issue = "32838")]
#![feature(global_allocator)]
#![feature(allocator_api)]
#![feature(alloc)]
}
#[derive(Debug, Clone, Copy)]
+#[repr(C)]
struct State {
// v0, v2 and v1, v3 show up in pairs in the algorithm,
// and simd implementations of SipHash will use vectors
/// [`Result`]: enum.Result.html
/// [`into_iter`]: ../iter/trait.IntoIterator.html#tymethod.into_iter
/// [`IntoIterator`]: ../iter/trait.IntoIterator.html
-#[derive(Debug)]
+#[derive(Clone, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub struct IntoIter<T> { inner: Option<T> }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// FIXME https://github.com/kripken/emscripten/issues/4563
-// NB we have to actually not compile this test to avoid
-// an undefined symbol error
-#![cfg(not(target_os = "emscripten"))]
-
use core::num::flt2dec::estimator::*;
#[test]
We are gradually replacing this pass-based code with an alternative
setup based on on-demand **queries**. In the query-model, we work
backwards, executing a *query* that expresses our ultimate goal (e.g.,
-"compiler this crate"). This query in turn may make other queries
+"compile this crate"). This query in turn may make other queries
(e.g., "get me a list of all modules in the crate"). Those queries
make other queries that ultimately bottom out in the base operations,
like parsing the input, running the type-checker, and so forth. This
things. This glossary attempts to list them and give you a few
pointers for understanding them better.
-- AST -- the **abstract syntax tree** produced the `syntax` crate; reflects user syntax
+- AST -- the **abstract syntax tree** produced by the `syntax` crate; reflects user syntax
very closely.
- codegen unit -- when we produce LLVM IR, we group the Rust code into a number of codegen
units. Each of these units is processed by LLVM independently from one another,
[] TypeOfItem(DefId),
[] GenericsOfItem(DefId),
[] PredicatesOfItem(DefId),
+ [] InferredOutlivesOf(DefId),
[] SuperPredicatesOfItem(DefId),
[] TraitDefOfItem(DefId),
[] AdtDefOfItem(DefId),
[] LookupDeprecationEntry(DefId),
[] ItemBodyNestedBodies(DefId),
[] ConstIsRvaluePromotableToStatic(DefId),
+ [] RvaluePromotableMap(DefId),
[] ImplParent(DefId),
[] TraitOfItem(DefId),
[] IsExportedSymbol(DefId),
[] PostorderCnums,
[] HasCloneClosures(CrateNum),
[] HasCopyClosures(CrateNum),
+ [] EraseRegionsTy { ty: Ty<'tcx> },
[] Freevars(DefId),
[] MaybeUnusedTraitImport(DefId),
};
// Err(err) => #[allow(unreachable_code)]
- // return Carrier::from_error(From::from(err)),
+ // return Try::from_error(From::from(err)),
let err_arm = {
let err_ident = self.str_to_ident("err");
let err_local = self.pat_ident(e.span, err_ident);
// except according to those terms.
use rustc_data_structures::stable_hasher;
-use std::mem;
-use std::slice;
#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, RustcEncodable, RustcDecodable)]
pub struct Fingerprint(u64, u64);
}
impl stable_hasher::StableHasherResult for Fingerprint {
- fn finish(mut hasher: stable_hasher::StableHasher<Self>) -> Self {
- let hash_bytes: &[u8] = hasher.finalize();
-
- assert!(hash_bytes.len() >= mem::size_of::<u64>() * 2);
- let hash_bytes: &[u64] = unsafe {
- slice::from_raw_parts(hash_bytes.as_ptr() as *const u64, 2)
- };
-
- // The bytes returned bytes the Blake2B hasher are always little-endian.
- Fingerprint(u64::from_le(hash_bytes[0]), u64::from_le(hash_bytes[1]))
+ fn finish(hasher: stable_hasher::StableHasher<Self>) -> Self {
+ let (_0, _1) = hasher.finalize();
+ Fingerprint(_0, _1)
}
}
FnPtrAddrCast
});
-impl_stable_hash_for!(struct ::middle::region::FirstStatementIndex { idx });
+impl_stable_hash_for!(tuple_struct ::middle::region::FirstStatementIndex { idx });
impl_stable_hash_for!(struct ::middle::region::Scope { id, code });
impl<'gcx> ToStableHashKey<StableHashingContext<'gcx>> for region::Scope {
#![cfg_attr(stage0, feature(const_fn))]
#![cfg_attr(not(stage0), feature(const_atomic_bool_new))]
-#![recursion_limit="256"]
+#![recursion_limit="512"]
extern crate arena;
#[macro_use] extern crate bitflags;
-> FxHashMap<hir::ItemLocalId, Vec<CFGIndex>> {
let mut index = FxHashMap();
- // FIXME (#6298): Would it be better to fold formals from decl
+ // FIXME(#15020) Would it be better to fold formals from decl
// into cfg itself? i.e. introduce a fn-based flow-graph in
// addition to the current block-based flow-graph, rather than
// have to put traversals like this here?
use ty::{self, TyCtxt, adjustment};
use hir::{self, PatKind};
-
+use std::rc::Rc;
use syntax::ast;
use syntax::ptr::P;
use syntax_pos::Span;
+use util::nodemap::ItemLocalMap;
///////////////////////////////////////////////////////////////////////////
// The Delegate trait
}
impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx, 'tcx> {
+ /// Creates the ExprUseVisitor, configuring it with the various options provided:
+ ///
+ /// - `delegate` -- who receives the callbacks
+ /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
+ /// - `region_scope_tree` --- region scope tree for the code being analyzed
+ /// - `tables` --- typeck results for the code being analyzed
+ /// - `rvalue_promotable_map` --- if you care about rvalue promotion, then provide
+ /// the map here (it can be computed with `tcx.rvalue_promotable_map(def_id)`).
+ /// `None` means that rvalues will be given more conservative lifetimes.
+ ///
+ /// See also `with_infer`, which is used *during* typeck.
pub fn new(delegate: &'a mut (Delegate<'tcx>+'a),
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
region_scope_tree: &'a region::ScopeTree,
- tables: &'a ty::TypeckTables<'tcx>)
+ tables: &'a ty::TypeckTables<'tcx>,
+ rvalue_promotable_map: Option<Rc<ItemLocalMap<bool>>>)
-> Self
{
ExprUseVisitor {
- mc: mc::MemCategorizationContext::new(tcx, region_scope_tree, tables),
+ mc: mc::MemCategorizationContext::new(tcx,
+ region_scope_tree,
+ tables,
+ rvalue_promotable_map),
delegate,
param_env,
}
use std::fmt;
use std::rc::Rc;
+use util::nodemap::ItemLocalMap;
#[derive(Clone, PartialEq)]
pub enum Categorization<'tcx> {
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
pub region_scope_tree: &'a region::ScopeTree,
pub tables: &'a ty::TypeckTables<'tcx>,
+ rvalue_promotable_map: Option<Rc<ItemLocalMap<bool>>>,
infcx: Option<&'a InferCtxt<'a, 'gcx, 'tcx>>,
}
impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
region_scope_tree: &'a region::ScopeTree,
- tables: &'a ty::TypeckTables<'tcx>)
+ tables: &'a ty::TypeckTables<'tcx>,
+ rvalue_promotable_map: Option<Rc<ItemLocalMap<bool>>>)
-> MemCategorizationContext<'a, 'tcx, 'tcx> {
- MemCategorizationContext { tcx, region_scope_tree, tables, infcx: None }
+ MemCategorizationContext {
+ tcx,
+ region_scope_tree,
+ tables,
+ rvalue_promotable_map,
+ infcx: None
+ }
}
}
impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
+ /// Creates a `MemCategorizationContext` during type inference.
+ /// This is used during upvar analysis and a few other places.
+ /// Because the typeck tables are not yet complete, the results
+ /// from the analysis must be used with caution:
+ ///
+ /// - rvalue promotions are not known, so the lifetimes of
+ /// temporaries may be overly conservative;
+ /// - similarly, as the results of upvar analysis are not yet
+ /// known, the results around upvar accesses may be incorrect.
pub fn with_infer(infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
region_scope_tree: &'a region::ScopeTree,
tables: &'a ty::TypeckTables<'tcx>)
-> MemCategorizationContext<'a, 'gcx, 'tcx> {
+ let tcx = infcx.tcx;
+
+ // Subtle: we can't do rvalue promotion analysis until the
+ // typeck phase is complete, which means that you can't trust
+ // the rvalue lifetimes that result, but that's ok, since we
+ // don't need to know those during type inference.
+ let rvalue_promotable_map = None;
+
MemCategorizationContext {
- tcx: infcx.tcx,
+ tcx,
region_scope_tree,
tables,
+ rvalue_promotable_map,
infcx: Some(infcx),
}
}
fn pat_ty(&self, pat: &hir::Pat) -> McResult<Ty<'tcx>> {
let base_ty = self.node_ty(pat.hir_id)?;
- // FIXME (Issue #18207): This code detects whether we are
- // looking at a `ref x`, and if so, figures out what the type
- // *being borrowed* is. But ideally we would put in a more
- // fundamental fix to this conflated use of the node id.
+ // This code detects whether we are looking at a `ref x`,
+ // and if so, figures out what the type *being borrowed* is.
let ret_ty = match pat.node {
PatKind::Binding(..) => {
let bm = *self.tables
span: Span,
expr_ty: Ty<'tcx>)
-> cmt<'tcx> {
- let promotable = self.tcx.rvalue_promotable_to_static.borrow().get(&id).cloned()
- .unwrap_or(false);
+ let hir_id = self.tcx.hir.node_to_hir_id(id);
+ let promotable = self.rvalue_promotable_map.as_ref().map(|m| m[&hir_id.local_id])
+ .unwrap_or(false);
// Always promote `[T; 0]` (even when e.g. borrowed mutably).
let promotable = match expr_ty.sty {
let re = if promotable {
self.tcx.types.re_static
} else {
- self.temporary_scope(self.tcx.hir.node_to_hir_id(id).local_id)
+ self.temporary_scope(hir_id.local_id)
};
let ret = self.cat_rvalue(id, span, re, expr_ty);
debug!("cat_rvalue_node ret {:?}", ret);
pub first_statement_index: FirstStatementIndex,
}
-#[derive(Clone, PartialEq, PartialOrd, Eq, Ord, Hash, RustcEncodable,
- RustcDecodable, Copy)]
-pub struct FirstStatementIndex { pub idx: u32 }
-
-impl Idx for FirstStatementIndex {
- fn new(idx: usize) -> Self {
- assert!(idx <= SCOPE_DATA_REMAINDER_MAX as usize);
- FirstStatementIndex { idx: idx as u32 }
- }
-
- fn index(self) -> usize {
- self.idx as usize
- }
-}
-
-impl fmt::Debug for FirstStatementIndex {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&self.index(), formatter)
- }
-}
+newtype_index!(FirstStatementIndex
+ {
+ DEBUG_NAME = "",
+ MAX = SCOPE_DATA_REMAINDER_MAX,
+ });
impl From<ScopeData> for Scope {
#[inline]
SCOPE_DATA_DESTRUCTION => ScopeData::Destruction(self.id),
idx => ScopeData::Remainder(BlockRemainder {
block: self.id,
- first_statement_index: FirstStatementIndex { idx }
+ first_statement_index: FirstStatementIndex::new(idx as usize)
})
}
}
hir::ExprAssignOp(..) | hir::ExprIndex(..) |
hir::ExprUnary(..) | hir::ExprCall(..) | hir::ExprMethodCall(..) => {
- // FIXME(#6268) Nested method calls
+ // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls
//
// The lifetimes for a call or method call look as follows:
//
// Here, the expression `[...]` has an extended lifetime due to rule
// A, but the inner rvalues `a()` and `b()` have an extended lifetime
// due to rule C.
- //
- // FIXME(#6308) -- Note that `[]` patterns work more smoothly post-DST.
if let Some(expr) = init {
record_rvalue_scope_if_borrow_expr(visitor, &expr, blk_scope);
}
// A module for searching for libraries
-// FIXME (#2658): I'm not happy how this module turned out. Should
-// probably just be folded into cstore.
pub struct FileSearch<'a> {
pub sysroot: &'a Path,
fn is_type_parameter(ty: Ty) -> bool {
match ty.sty {
- // FIXME(#20590) straighten story about projection types
ty::TyProjection(..) | ty::TyParam(..) => true,
_ => false,
}
};
if obligation.predicate.skip_binder().self_ty().is_ty_var() {
- // FIXME(#20297): Self is a type variable (e.g. `_: AsRef<str>`).
+ // Self is a type variable (e.g. `_: AsRef<str>`).
//
// This is somewhat problematic, as the current scheme can't really
// handle it turning to be a projection. This does end up as truly
// ambiguous in most cases anyway.
//
- // Until this is fixed, take the fast path out - this also improves
+ // Take the fast path out - this also improves
// performance by preventing assemble_candidates_from_impls from
// matching every impl for this trait.
return Ok(SelectionCandidateSet { vec: vec![], ambiguous: true });
{
debug!("assemble_candidates_for_projected_tys({:?})", obligation);
- // FIXME(#20297) -- just examining the self-type is very simplistic
-
// before we go into the whole skolemization thing, just
// quickly check if the self-type is a projection at all.
match obligation.predicate.0.trait_ref.self_ty().sty {
}
ty::TyClosure(def_id, ref substs) => {
- // FIXME(#27086). We are invariant w/r/t our
- // func_substs, but we don't see them as
- // constituent types; this seems RIGHT but also like
- // something that a normal type couldn't simulate. Is
- // this just a gap with the way that PhantomData and
- // OIBIT interact? That is, there is no way to say
- // "make me invariant with respect to this TYPE, but
- // do not act as though I can reach it"
substs.upvar_tys(def_id, self.tcx()).collect()
}
Often, we wish to write code that explicitly asserts that it is not
taking place during inference. In that case, there is no "local"
arena, and all the types that you can access are allocated in the
-global arena. To express this, the idea is to us the same lifetime
+global arena. To express this, the idea is to use the same lifetime
for the `'gcx` and `'tcx` parameters of `TyCtxt`. Just to be a touch
confusing, we tend to use the name `'tcx` in such contexts. Here is an
example:
The `sty` field (the origin of this name is unclear to me; perhaps
structural type?) is of type `TypeVariants<'tcx>`, which is an enum
-definined all of the different kinds of types in the compiler.
+defining all of the different kinds of types in the compiler.
> NB: inspecting the `sty` field on types during type inference can be
-> risky, as there are may be inference variables and other things to
+> risky, as there may be inference variables and other things to
> consider, or sometimes types are not yet known that will become
> known later.).
> you are going to be testing for type equality, you probably need to
> start looking into the inference code to do it right.
-You can also find various common types in the tcx itself by accessing
+You can also find various common types in the `tcx` itself by accessing
`tcx.types.bool`, `tcx.types.char`, etc (see `CommonTypes` for more).
### Beyond types: Other kinds of arena-allocated data structures
- `Substs`, allocated with `mk_substs` -- this will intern a slice of types, often used to
specify the values to be substituted for generics (e.g., `HashMap<i32, u32>`
- would be represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`.
+ would be represented as a slice `&'tcx [tcx.types.i32, tcx.types.u32]`).
- `TraitRef`, typically passed by value -- a **trait reference**
consists of a reference to a trait along with its various type
parameters (including `Self`), like `i32: Display` (here, the def-id
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use ty::TypeVariants::*;
use ty::layout::{Layout, TargetDataLayout};
-use ty::inhabitedness::DefIdForest;
use ty::maps;
use ty::steal::Steal;
use ty::BindingMode;
// Internal cache for metadata decoding. No need to track deps on this.
pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
- // FIXME dep tracking -- should be harmless enough
- pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
-
- pub inhabitedness_cache: RefCell<FxHashMap<Ty<'tcx>, DefIdForest>>,
-
/// Caches the results of trait selection. This cache is used
/// for things that do not have to do with the parameters in scope.
pub selection_cache: traits::SelectionCache<'tcx>,
/// Merge this with `selection_cache`?
pub evaluation_cache: traits::EvaluationCache<'tcx>,
- /// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
- pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
-
/// The definite name of the current crate after taking into account
/// attributes, commandline parameters, etc.
pub crate_name: Symbol,
maps: maps::Maps::new(providers),
mir_passes,
rcache: RefCell::new(FxHashMap()),
- normalized_cache: RefCell::new(FxHashMap()),
- inhabitedness_cache: RefCell::new(FxHashMap()),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
- rvalue_promotable_to_static: RefCell::new(NodeMap()),
crate_name: Symbol::intern(crate_name),
data_layout,
layout_interner: RefCell::new(FxHashSet()),
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ty::{self, Ty, TyCtxt};
+use ty::fold::{TypeFolder, TypeFoldable};
+
+pub(super) fn provide(providers: &mut ty::maps::Providers) {
+ *providers = ty::maps::Providers {
+ erase_regions_ty,
+ ..*providers
+ };
+}
+
+fn erase_regions_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
+ // NB: use `super_fold_with` here. If we used `fold_with`, it
+ // could invoke the `erase_regions_ty` query recursively.
+ ty.super_fold_with(&mut RegionEraserVisitor { tcx })
+}
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+ /// Returns an equivalent value with all free regions removed (note
+ /// that late-bound regions remain, because they are important for
+ /// subtyping, but they are anonymized and normalized as well)..
+ pub fn erase_regions<T>(self, value: &T) -> T
+ where T : TypeFoldable<'tcx>
+ {
+ let value1 = value.fold_with(&mut RegionEraserVisitor { tcx: self });
+ debug!("erase_regions({:?}) = {:?}", value, value1);
+ value1
+ }
+}
+
+struct RegionEraserVisitor<'a, 'gcx: 'tcx, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+}
+
+impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraserVisitor<'a, 'gcx, 'tcx> {
+ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> {
+ self.tcx
+ }
+
+ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+ if let Some(ty_lifted) = self.tcx.lift_to_global(&ty) {
+ self.tcx.erase_regions_ty(ty_lifted)
+ } else {
+ ty.super_fold_with(self)
+ }
+ }
+
+ fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
+ where T : TypeFoldable<'tcx>
+ {
+ let u = self.tcx.anonymize_late_bound_regions(t);
+ u.super_fold_with(self)
+ }
+
+ fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
+ // because late-bound regions affect subtyping, we can't
+ // erase the bound/free distinction, but we can replace
+ // all free regions with 'erased.
+ //
+ // Note that we *CAN* replace early-bound regions -- the
+ // type system never "sees" those, they get substituted
+ // away. In trans, they will always be erased to 'erased
+ // whenever a substitution occurs.
+ match *r {
+ ty::ReLateBound(..) => r,
+ _ => self.tcx.types.re_erased
+ }
+ }
+}
+
}
}
-///////////////////////////////////////////////////////////////////////////
-// Region eraser
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
- /// Returns an equivalent value with all free regions removed (note
- /// that late-bound regions remain, because they are important for
- /// subtyping, but they are anonymized and normalized as well)..
- pub fn erase_regions<T>(self, value: &T) -> T
- where T : TypeFoldable<'tcx>
- {
- let value1 = value.fold_with(&mut RegionEraser(self));
- debug!("erase_regions({:?}) = {:?}",
- value, value1);
- return value1;
-
- struct RegionEraser<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(TyCtxt<'a, 'gcx, 'tcx>);
-
- impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for RegionEraser<'a, 'gcx, 'tcx> {
- fn tcx<'b>(&'b self) -> TyCtxt<'b, 'gcx, 'tcx> { self.0 }
-
- fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if let Some(u) = self.tcx().normalized_cache.borrow().get(&ty).cloned() {
- return u;
- }
-
- // FIXME(eddyb) should local contexts have a cache too?
- if let Some(ty_lifted) = self.tcx().lift_to_global(&ty) {
- let tcx = self.tcx().global_tcx();
- let t_norm = ty_lifted.super_fold_with(&mut RegionEraser(tcx));
- tcx.normalized_cache.borrow_mut().insert(ty_lifted, t_norm);
- t_norm
- } else {
- ty.super_fold_with(self)
- }
- }
-
- fn fold_binder<T>(&mut self, t: &ty::Binder<T>) -> ty::Binder<T>
- where T : TypeFoldable<'tcx>
- {
- let u = self.tcx().anonymize_late_bound_regions(t);
- u.super_fold_with(self)
- }
-
- fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- // because late-bound regions affect subtyping, we can't
- // erase the bound/free distinction, but we can replace
- // all free regions with 'erased.
- //
- // Note that we *CAN* replace early-bound regions -- the
- // type system never "sees" those, they get substituted
- // away. In trans, they will always be erased to 'erased
- // whenever a substitution occurs.
- match *r {
- ty::ReLateBound(..) => r,
- _ => self.tcx().types.re_erased
- }
- }
- }
- }
-}
-
///////////////////////////////////////////////////////////////////////////
// Region shifter
//
use util::nodemap::{FxHashMap, FxHashSet};
use ty::context::TyCtxt;
-use ty::{AdtDef, VariantDef, FieldDef, TyS};
+use ty::{AdtDef, VariantDef, FieldDef, Ty, TyS};
use ty::{DefId, Substs};
use ty::{AdtKind, Visibility};
use ty::TypeVariants::*;
// This code should only compile in modules where the uninhabitedness of Foo is
// visible.
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+ /// Checks whether a type is visibly uninhabited from a particular module.
+ /// # Example
+ /// ```rust
+ /// enum Void {}
+ /// mod a {
+ /// pub mod b {
+ /// pub struct SecretlyUninhabited {
+ /// _priv: !,
+ /// }
+ /// }
+ /// }
+ ///
+ /// mod c {
+ /// pub struct AlsoSecretlyUninhabited {
+ /// _priv: Void,
+ /// }
+ /// mod d {
+ /// }
+ /// }
+ ///
+ /// struct Foo {
+ /// x: a::b::SecretlyUninhabited,
+ /// y: c::AlsoSecretlyUninhabited,
+ /// }
+ /// ```
+ /// In this code, the type `Foo` will only be visibly uninhabited inside the
+ /// modules b, c and d. This effects pattern-matching on `Foo` or types that
+ /// contain `Foo`.
+ ///
+ /// # Example
+ /// ```rust
+ /// let foo_result: Result<T, Foo> = ... ;
+ /// let Ok(t) = foo_result;
+ /// ```
+ /// This code should only compile in modules where the uninhabitedness of Foo is
+ /// visible.
+ pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
+ // To check whether this type is uninhabited at all (not just from the
+ // given node) you could check whether the forest is empty.
+ // ```
+ // forest.is_empty()
+ // ```
+ self.ty_inhabitedness_forest(ty).contains(self, module)
+ }
+
+ pub fn is_ty_uninhabited_from_all_modules(self, ty: Ty<'tcx>) -> bool {
+ !self.ty_inhabitedness_forest(ty).is_empty()
+ }
+
+ fn ty_inhabitedness_forest(self, ty: Ty<'tcx>) -> DefIdForest {
+ ty.uninhabited_from(&mut FxHashMap(), self)
+ }
+
+ pub fn is_enum_variant_uninhabited_from(self,
+ module: DefId,
+ variant: &'tcx VariantDef,
+ substs: &'tcx Substs<'tcx>)
+ -> bool
+ {
+ self.variant_inhabitedness_forest(variant, substs).contains(self, module)
+ }
+
+ pub fn is_variant_uninhabited_from_all_modules(self,
+ variant: &'tcx VariantDef,
+ substs: &'tcx Substs<'tcx>)
+ -> bool
+ {
+ !self.variant_inhabitedness_forest(variant, substs).is_empty()
+ }
+
+ fn variant_inhabitedness_forest(self, variant: &'tcx VariantDef, substs: &'tcx Substs<'tcx>)
+ -> DefIdForest {
+ // Determine the ADT kind:
+ let adt_def_id = self.adt_def_id_of_variant(variant);
+ let adt_kind = self.adt_def(adt_def_id).adt_kind();
+
+ // Compute inhabitedness forest:
+ variant.uninhabited_from(&mut FxHashMap(), self, substs, adt_kind)
+ }
+}
+
impl<'a, 'gcx, 'tcx> AdtDef {
/// Calculate the forest of DefIds from which this adt is visibly uninhabited.
- pub fn uninhabited_from(
- &self,
- visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- substs: &'tcx Substs<'tcx>) -> DefIdForest
+ fn uninhabited_from(
+ &self,
+ visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ substs: &'tcx Substs<'tcx>) -> DefIdForest
{
DefIdForest::intersection(tcx, self.variants.iter().map(|v| {
v.uninhabited_from(visited, tcx, substs, self.adt_kind())
impl<'a, 'gcx, 'tcx> VariantDef {
/// Calculate the forest of DefIds from which this variant is visibly uninhabited.
- pub fn uninhabited_from(
- &self,
- visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- substs: &'tcx Substs<'tcx>,
- adt_kind: AdtKind) -> DefIdForest
+ fn uninhabited_from(
+ &self,
+ visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ substs: &'tcx Substs<'tcx>,
+ adt_kind: AdtKind) -> DefIdForest
{
match adt_kind {
AdtKind::Union => {
impl<'a, 'gcx, 'tcx> FieldDef {
/// Calculate the forest of DefIds from which this field is visibly uninhabited.
- pub fn uninhabited_from(
- &self,
- visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
- tcx: TyCtxt<'a, 'gcx, 'tcx>,
- substs: &'tcx Substs<'tcx>,
- is_enum: bool) -> DefIdForest
+ fn uninhabited_from(
+ &self,
+ visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ substs: &'tcx Substs<'tcx>,
+ is_enum: bool) -> DefIdForest
{
let mut data_uninhabitedness = move || {
self.ty(tcx, substs).uninhabited_from(visited, tcx)
impl<'a, 'gcx, 'tcx> TyS<'tcx> {
/// Calculate the forest of DefIds from which this type is visibly uninhabited.
- pub fn uninhabited_from(
- &self,
- visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
- tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
- {
- match tcx.lift_to_global(&self) {
- Some(global_ty) => {
- {
- let cache = tcx.inhabitedness_cache.borrow();
- if let Some(forest) = cache.get(&global_ty) {
- return forest.clone();
- }
- }
- let forest = global_ty.uninhabited_from_inner(visited, tcx);
- let mut cache = tcx.inhabitedness_cache.borrow_mut();
- cache.insert(global_ty, forest.clone());
- forest
- },
- None => {
- let forest = self.uninhabited_from_inner(visited, tcx);
- forest
- },
- }
- }
-
- fn uninhabited_from_inner(
- &self,
- visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
- tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
+ fn uninhabited_from(
+ &self,
+ visited: &mut FxHashMap<DefId, FxHashSet<&'tcx Substs<'tcx>>>,
+ tcx: TyCtxt<'a, 'gcx, 'tcx>) -> DefIdForest
{
match self.sty {
TyAdt(def, substs) => {
impl<M: QueryConfig<Key=DefId>> QueryDescription for M {
default fn describe(tcx: TyCtxt, def_id: DefId) -> String {
- format!("processing `{}`", tcx.item_path_str(def_id))
+ if !tcx.sess.verbose() {
+ format!("processing `{}`", tcx.item_path_str(def_id))
+ } else {
+ let name = unsafe { ::std::intrinsics::type_name::<M>() };
+ format!("processing `{}` applied to `{:?}`", name, def_id)
+ }
}
}
}
}
+impl<'tcx> QueryDescription for queries::erase_regions_ty<'tcx> {
+ fn describe(_tcx: TyCtxt, ty: Ty<'tcx>) -> String {
+ format!("erasing regions from `{:?}`", ty)
+ }
+}
+
impl<'tcx> QueryDescription for queries::type_param_predicates<'tcx> {
fn describe(tcx: TyCtxt, (_, def_id): (DefId, DefId)) -> String {
let id = tcx.hir.as_local_node_id(def_id).unwrap();
}
}
+impl<'tcx> QueryDescription for queries::rvalue_promotable_map<'tcx> {
+ fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+ format!("checking which parts of `{}` are promotable to static",
+ tcx.item_path_str(def_id))
+ }
+}
+
impl<'tcx> QueryDescription for queries::is_mir_available<'tcx> {
fn describe(tcx: TyCtxt, def_id: DefId) -> String {
format!("checking if item is mir available: `{}`",
use ty::layout::{Layout, LayoutError};
use ty::steal::Steal;
use ty::subst::Substs;
-use util::nodemap::{DefIdSet, DefIdMap};
+use util::nodemap::{DefIdSet, DefIdMap, ItemLocalMap};
use util::common::{profq_msg, ProfileQueriesMsg};
use rustc_data_structures::indexed_set::IdxSetBuf;
/// (inferred) variance.
[] fn variances_of: ItemVariances(DefId) -> Rc<Vec<ty::Variance>>,
+ /// Maps from def-id of a type to its (inferred) outlives.
+ [] fn inferred_outlives_of: InferredOutlivesOf(DefId) -> Vec<ty::Predicate<'tcx>>,
+
/// Maps from an impl/trait def-id to a list of the def-ids of its items
[] fn associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>>,
[] fn is_exported_symbol: IsExportedSymbol(DefId) -> bool,
[] fn item_body_nested_bodies: ItemBodyNestedBodies(DefId) -> ExternBodyNestedBodies,
[] fn const_is_rvalue_promotable_to_static: ConstIsRvaluePromotableToStatic(DefId) -> bool,
+ [] fn rvalue_promotable_map: RvaluePromotableMap(DefId) -> Rc<ItemLocalMap<bool>>,
[] fn is_mir_available: IsMirAvailable(DefId) -> bool,
[] fn vtable_methods: vtable_methods_node(ty::PolyTraitRef<'tcx>)
-> Rc<Vec<Option<(DefId, &'tcx Substs<'tcx>)>>>,
[] fn has_copy_closures: HasCopyClosures(CrateNum) -> bool,
[] fn has_clone_closures: HasCloneClosures(CrateNum) -> bool,
+
+ // Erases regions from `ty` to yield a new type.
+ // Normally you would just use `tcx.erase_regions(&value)`,
+ // however, which uses this query as a kind of cache.
+ [] fn erase_regions_ty: erase_regions_ty(Ty<'tcx>) -> Ty<'tcx>,
}
//////////////////////////////////////////////////////////////////////
// These functions are little shims used to find the dep-node for a
// given query when there is not a *direct* mapping:
+fn erase_regions_ty<'tcx>(ty: Ty<'tcx>) -> DepConstructor<'tcx> {
+ DepConstructor::EraseRegionsTy { ty }
+}
+
fn type_param_predicates<'tcx>((item_id, param_id): (DefId, DefId)) -> DepConstructor<'tcx> {
DepConstructor::TypeParamPredicates {
item_id,
//! that generate the actual methods on tcx which find and execute the
//! provider, manage the caches, and so forth.
-use dep_graph::{DepNodeIndex, DepNode, DepKind};
+use dep_graph::{DepNodeIndex, DepNode, DepKind, DepNodeColor};
use errors::{Diagnostic, DiagnosticBuilder};
use ty::{TyCtxt};
use ty::maps::Query; // NB: actually generated by the macros in this file
Ok(result)
}
+
+ /// Try to read a node index for the node dep_node.
+ /// A node will have an index, when it's already been marked green, or when we can mark it
+ /// green. This function will mark the current task as a reader of the specified node, when
+ /// the a node index can be found for that node.
+ pub(super) fn try_mark_green_and_read(self, dep_node: &DepNode) -> Option<DepNodeIndex> {
+ match self.dep_graph.node_color(dep_node) {
+ Some(DepNodeColor::Green(dep_node_index)) => {
+ self.dep_graph.read_index(dep_node_index);
+ Some(dep_node_index)
+ }
+ Some(DepNodeColor::Red) => {
+ None
+ }
+ None => {
+ // try_mark_green (called below) will panic when full incremental
+ // compilation is disabled. If that's the case, we can't try to mark nodes
+ // as green anyway, so we can safely return None here.
+ if !self.dep_graph.is_fully_enabled() {
+ return None;
+ }
+ match self.dep_graph.try_mark_green(self, &dep_node) {
+ Some(dep_node_index) => {
+ debug_assert!(self.dep_graph.is_green(dep_node_index));
+ self.dep_graph.read_index(dep_node_index);
+ Some(dep_node_index)
+ }
+ None => {
+ None
+ }
+ }
+ }
+ }
+ }
}
// If enabled, send a message to the profile-queries thread
}
if !dep_node.kind.is_input() {
- use dep_graph::DepNodeColor;
- if let Some(DepNodeColor::Green(dep_node_index)) = tcx.dep_graph
- .node_color(&dep_node) {
+ if let Some(dep_node_index) = tcx.try_mark_green_and_read(&dep_node) {
profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
- tcx.dep_graph.read_index(dep_node_index);
- return Self::load_from_disk_and_cache_in_memory(tcx,
- key,
- span,
- dep_node_index)
- }
-
- debug!("ty::queries::{}::try_get_with(key={:?}) - running try_mark_green",
- stringify!($name),
- key);
-
- if let Some(dep_node_index) = tcx.dep_graph.try_mark_green(tcx, &dep_node) {
- debug_assert!(tcx.dep_graph.is_green(dep_node_index));
- profq_msg!(tcx, ProfileQueriesMsg::CacheHit);
- tcx.dep_graph.read_index(dep_node_index);
return Self::load_from_disk_and_cache_in_memory(tcx,
key,
span,
// Ensuring an "input" or anonymous query makes no sense
assert!(!dep_node.kind.is_anon());
assert!(!dep_node.kind.is_input());
- use dep_graph::DepNodeColor;
- match tcx.dep_graph.node_color(&dep_node) {
- Some(DepNodeColor::Green(dep_node_index)) => {
- tcx.dep_graph.read_index(dep_node_index);
- }
- Some(DepNodeColor::Red) => {
- // A DepNodeColor::Red DepNode means that this query was executed
- // before. We can not call `dep_graph.read()` here as we don't have
- // the DepNodeIndex. Instead, We call the query again to issue the
- // appropriate `dep_graph.read()` call. The performance cost this
- // introduces should be negligible as we'll immediately hit the
- // in-memory cache.
- let _ = tcx.$name(key);
- }
- None => {
- // Huh
- if !tcx.dep_graph.is_fully_enabled() {
- let _ = tcx.$name(key);
- return;
- }
- match tcx.dep_graph.try_mark_green(tcx, &dep_node) {
- Some(dep_node_index) => {
- debug_assert!(tcx.dep_graph.is_green(dep_node_index));
- tcx.dep_graph.read_index(dep_node_index);
- }
- None => {
- let _ = tcx.$name(key);
- }
- }
- }
+ if tcx.try_mark_green_and_read(&dep_node).is_none() {
+ // A None return from `try_mark_green_and_read` means that this is either
+ // a new dep node or that the dep node has already been marked red.
+ // Either way, we can't call `dep_graph.read()` as we don't have the
+ // DepNodeIndex. We must invoke the query itself. The performance cost
+ // this introduces should be negligible as we'll immediately hit the
+ // in-memory cache, or another query down the line will.
+ let _ = tcx.$name(key);
}
}
DepKind::CompileCodegenUnit |
DepKind::FulfillObligation |
DepKind::VtableMethods |
+ DepKind::EraseRegionsTy |
// These are just odd
DepKind::Null |
DepKind::TypeOfItem => { force!(type_of, def_id!()); }
DepKind::GenericsOfItem => { force!(generics_of, def_id!()); }
DepKind::PredicatesOfItem => { force!(predicates_of, def_id!()); }
+ DepKind::InferredOutlivesOf => { force!(inferred_outlives_of, def_id!()); }
DepKind::SuperPredicatesOfItem => { force!(super_predicates_of, def_id!()); }
DepKind::TraitDefOfItem => { force!(trait_def, def_id!()); }
DepKind::AdtDefOfItem => { force!(adt_def, def_id!()); }
DepKind::ConstIsRvaluePromotableToStatic => {
force!(const_is_rvalue_promotable_to_static, def_id!());
}
+ DepKind::RvaluePromotableMap => { force!(rvalue_promotable_map, def_id!()); }
DepKind::ImplParent => { force!(impl_parent, def_id!()); }
DepKind::TraitOfItem => { force!(trait_of_item, def_id!()); }
DepKind::IsExportedSymbol => { force!(is_exported_symbol, def_id!()); }
use hir::{map as hir_map, FreevarMap, TraitMap};
use hir::def::{Def, CtorKind, ExportMap};
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use hir::map::DefPathData;
use ich::StableHashingContext;
use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
pub mod binding;
pub mod cast;
pub mod error;
+mod erase_regions;
pub mod fast_reject;
pub mod fold;
pub mod inhabitedness;
}
}
+ /// Given a `VariantDef`, returns the def-id of the `AdtDef` of which it is a part.
+ pub fn adt_def_id_of_variant(self, variant_def: &'tcx VariantDef) -> DefId {
+ let def_key = self.def_key(variant_def.did);
+ match def_key.disambiguated_data.data {
+ // for enum variants and tuple structs, the def-id of the ADT itself
+ // is the *parent* of the variant
+ DefPathData::EnumVariant(..) | DefPathData::StructCtor =>
+ DefId { krate: variant_def.did.krate, index: def_key.parent.unwrap() },
+
+ // otherwise, for structs and unions, they share a def-id
+ _ => variant_def.did,
+ }
+ }
+
pub fn item_name(self, id: DefId) -> InternedString {
if let Some(id) = self.hir.as_local_node_id(id) {
self.hir.name(id).as_str()
pub fn provide(providers: &mut ty::maps::Providers) {
util::provide(providers);
context::provide(providers);
+ erase_regions::provide(providers);
*providers = ty::maps::Providers {
associated_item,
associated_item_def_ids,
// projection).
match ty.sty {
ty::TyClosure(def_id, ref substs) => {
- // FIXME(#27086). We do not accumulate from substs, since they
- // don't represent reachable data. This means that, in
- // practice, some of the lifetime parameters might not
- // be in scope when the body runs, so long as there is
- // no reachable data with that lifetime. For better or
- // worse, this is consistent with fn types, however,
- // which can also encapsulate data in this fashion
- // (though it's somewhat harder, and typically
- // requires virtual dispatch).
- //
- // Note that changing this (in a naive way, at least)
- // causes regressions for what appears to be perfectly
- // reasonable code like this:
- //
- // ```
- // fn foo<'a>(p: &Data<'a>) {
- // bar(|q: &mut Parser| q.read_addr())
- // }
- // fn bar(p: Box<FnMut(&mut Parser)+'static>) {
- // }
- // ```
- //
- // Note that `p` (and `'a`) are not used in the
- // closure at all, but to meet the requirement that
- // the closure type `C: 'static` (so it can be coerced
- // to the object type), we get the requirement that
- // `'a: 'static` since `'a` appears in the closure
- // type `C`.
- //
- // A smarter fix might "prune" unused `func_substs` --
- // this would avoid breaking simple examples like
- // this, but would still break others (which might
- // indeed be invalid, depending on your POV). Pruning
- // would be a subtle process, since we have to see
- // what func/type parameters are used and unused,
- // taking into consideration UFCS and so forth.
for upvar_ty in substs.upvar_tys(def_id, *self) {
self.compute_components(upvar_ty, out);
use syntax::abi;
use syntax::ast::{self, Name};
use syntax::symbol::keywords;
-use util::nodemap::FxHashMap;
use serialize;
}
}
- /// Checks whether a type is visibly uninhabited from a particular module.
- /// # Example
- /// ```rust
- /// enum Void {}
- /// mod a {
- /// pub mod b {
- /// pub struct SecretlyUninhabited {
- /// _priv: !,
- /// }
- /// }
- /// }
- ///
- /// mod c {
- /// pub struct AlsoSecretlyUninhabited {
- /// _priv: Void,
- /// }
- /// mod d {
- /// }
- /// }
- ///
- /// struct Foo {
- /// x: a::b::SecretlyUninhabited,
- /// y: c::AlsoSecretlyUninhabited,
- /// }
- /// ```
- /// In this code, the type `Foo` will only be visibly uninhabited inside the
- /// modules b, c and d. This effects pattern-matching on `Foo` or types that
- /// contain `Foo`.
- ///
- /// # Example
- /// ```rust
- /// let foo_result: Result<T, Foo> = ... ;
- /// let Ok(t) = foo_result;
- /// ```
- /// This code should only compile in modules where the uninhabitedness of Foo is
- /// visible.
- pub fn is_uninhabited_from(&self, module: DefId, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
- let mut visited = FxHashMap::default();
- let forest = self.uninhabited_from(&mut visited, tcx);
-
- // To check whether this type is uninhabited at all (not just from the
- // given node) you could check whether the forest is empty.
- // ```
- // forest.is_empty()
- // ```
- forest.contains(tcx, module)
- }
-
pub fn is_primitive(&self) -> bool {
match self.sty {
TyBool | TyChar | TyInt(_) | TyUint(_) | TyFloat(_) => true,
-**FIXME #10520: Restrictions against mutating the base pointer.** When
-an `&mut` pointer is frozen or claimed, we currently pass along the
+**FIXME [RFC 1751](https://github.com/rust-lang/rfcs/issues/1751)
+Restrictions against mutating the base pointer.**
+When an `&mut` pointer is frozen or claimed, we currently pass along the
restriction against MUTATE to the base pointer. I do not believe this
restriction is needed. It dates from the days when we had a way to
mutate that preserved the value being mutated (i.e., swap). Nowadays
all_loans,
param_env,
};
- euv::ExprUseVisitor::new(&mut clcx, bccx.tcx, param_env, &bccx.region_scope_tree, bccx.tables)
+ let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
+ euv::ExprUseVisitor::new(&mut clcx,
+ bccx.tcx,
+ param_env,
+ &bccx.region_scope_tree,
+ bccx.tables,
+ Some(rvalue_promotable_map))
.consume_body(body);
}
debug!("check_if_path_is_moved(id={:?}, use_kind={:?}, lp={:?})",
id, use_kind, lp);
- // FIXME (22079): if you find yourself tempted to cut and paste
+ // FIXME: if you find yourself tempted to cut and paste
// the body below and then specializing the error reporting,
// consider refactoring this instead!
// the path must be initialized to prevent a case of
// partial reinitialization
//
- // FIXME (22079): could refactor via hypothetical
+ // FIXME: could refactor via hypothetical
// generalized check_if_path_is_moved
let loan_path = owned_ptr_base_path_rc(lp_base);
self.move_data.each_move_of(id, &loan_path, |_, _| {
move_error_collector: move_error::MoveErrorCollector::new(),
};
- euv::ExprUseVisitor::new(&mut glcx, bccx.tcx, param_env, &bccx.region_scope_tree, bccx.tables)
+ let rvalue_promotable_map = bccx.tcx.rvalue_promotable_map(def_id);
+ euv::ExprUseVisitor::new(&mut glcx,
+ bccx.tcx,
+ param_env,
+ &bccx.region_scope_tree,
+ bccx.tables,
+ Some(rvalue_promotable_map))
.consume_body(bccx.body);
glcx.report_potential_errors();
self.all_loans.push(loan);
// if loan_gen_scope != borrow_id {
- // FIXME(#6268) Nested method calls
+ // FIXME(https://github.com/rust-lang/rfcs/issues/811) Nested method calls
//
// Typically, the scope of the loan includes the point at
// which the loan is originated. This
//let restr = restrictions::compute_restrictions(
// self.bccx, borrow_span, cmt, RESTR_EMPTY);
//let loan = {
- // let all_loans = &mut *self.all_loans; // FIXME(#5074)
// Loan {
- // index: all_loans.len(),
+ // index: self.all_loans.len(),
// loan_path,
// cmt,
// mutbl: ConstMutability,
use rustc::hir::def_id::DefId;
use rustc::hir::RangeEnd;
-use rustc::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::mir::Field;
use rustc::util::common::ErrorReported;
fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
if self.tcx.sess.features.borrow().never_type {
- ty.is_uninhabited_from(self.module, self.tcx)
+ self.tcx.is_ty_uninhabited_from(self.module, ty)
} else {
false
}
fn is_variant_uninhabited(&self,
variant: &'tcx ty::VariantDef,
- substs: &'tcx ty::subst::Substs<'tcx>) -> bool
+ substs: &'tcx ty::subst::Substs<'tcx>)
+ -> bool
{
if self.tcx.sess.features.borrow().never_type {
- let forest = variant.uninhabited_from(
- &mut FxHashMap::default(), self.tcx, substs, AdtKind::Enum
- );
- forest.contains(self.tcx, self.module)
+ self.tcx.is_enum_variant_uninhabited_from(self.module, variant, substs)
} else {
false
}
let module = self.tcx.hir.get_module_parent(scrut.id);
if inlined_arms.is_empty() {
let scrutinee_is_uninhabited = if self.tcx.sess.features.borrow().never_type {
- pat_ty.is_uninhabited_from(module, self.tcx)
+ self.tcx.is_ty_uninhabited_from(module, pat_ty)
} else {
self.conservative_is_uninhabited(pat_ty)
};
let mut checker = MutationChecker {
cx,
};
- ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_scope_tree, cx.tables)
+ ExprUseVisitor::new(&mut checker, cx.tcx, cx.param_env, cx.region_scope_tree, cx.tables, None)
.walk_expr(guard);
}
(@type[$type:ident] @max[$max:expr] @debug_name[$debug_name:expr]) => (
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
RustcEncodable, RustcDecodable)]
- pub struct $type(u32);
+ pub struct $type(pub u32);
impl Idx for $type {
fn new(value: usize) -> Self {
// Replace existing default for max
(@type[$type:ident] @max[$_max:expr] @debug_name[$debug_name:expr]
MAX = $max:expr, $($tokens:tt)*) => (
- newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $(tokens)*);
+ newtype_index!(@type[$type] @max[$max] @debug_name[$debug_name] $($tokens)*);
);
// Replace existing default for debug_name
#![feature(fn_traits)]
#![feature(unsize)]
#![feature(i128_type)]
+#![feature(i128)]
#![feature(conservative_impl_trait)]
#![feature(specialization)]
pub mod indexed_set;
pub mod indexed_vec;
pub mod obligation_forest;
+pub mod sip128;
pub mod snapshot_map;
pub mod snapshot_vec;
pub mod stable_hasher;
--- /dev/null
+// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! This is a copy of `core::hash::sip` adapted to providing 128 bit hashes.
+
+use std::cmp;
+use std::hash::Hasher;
+use std::slice;
+use std::ptr;
+use std::mem;
+
+#[derive(Debug, Clone)]
+pub struct SipHasher128 {
+ k0: u64,
+ k1: u64,
+ length: usize, // how many bytes we've processed
+ state: State, // hash State
+ tail: u64, // unprocessed bytes le
+ ntail: usize, // how many bytes in tail are valid
+}
+
+#[derive(Debug, Clone, Copy)]
+#[repr(C)]
+struct State {
+ // v0, v2 and v1, v3 show up in pairs in the algorithm,
+ // and simd implementations of SipHash will use vectors
+ // of v02 and v13. By placing them in this order in the struct,
+ // the compiler can pick up on just a few simd optimizations by itself.
+ v0: u64,
+ v2: u64,
+ v1: u64,
+ v3: u64,
+}
+
+macro_rules! compress {
+ ($state:expr) => ({
+ compress!($state.v0, $state.v1, $state.v2, $state.v3)
+ });
+ ($v0:expr, $v1:expr, $v2:expr, $v3:expr) =>
+ ({
+ $v0 = $v0.wrapping_add($v1); $v1 = $v1.rotate_left(13); $v1 ^= $v0;
+ $v0 = $v0.rotate_left(32);
+ $v2 = $v2.wrapping_add($v3); $v3 = $v3.rotate_left(16); $v3 ^= $v2;
+ $v0 = $v0.wrapping_add($v3); $v3 = $v3.rotate_left(21); $v3 ^= $v0;
+ $v2 = $v2.wrapping_add($v1); $v1 = $v1.rotate_left(17); $v1 ^= $v2;
+ $v2 = $v2.rotate_left(32);
+ });
+}
+
+/// Load an integer of the desired type from a byte stream, in LE order. Uses
+/// `copy_nonoverlapping` to let the compiler generate the most efficient way
+/// to load it from a possibly unaligned address.
+///
+/// Unsafe because: unchecked indexing at i..i+size_of(int_ty)
+macro_rules! load_int_le {
+ ($buf:expr, $i:expr, $int_ty:ident) =>
+ ({
+ debug_assert!($i + mem::size_of::<$int_ty>() <= $buf.len());
+ let mut data = 0 as $int_ty;
+ ptr::copy_nonoverlapping($buf.get_unchecked($i),
+ &mut data as *mut _ as *mut u8,
+ mem::size_of::<$int_ty>());
+ data.to_le()
+ });
+}
+
+/// Load an u64 using up to 7 bytes of a byte slice.
+///
+/// Unsafe because: unchecked indexing at start..start+len
+#[inline]
+unsafe fn u8to64_le(buf: &[u8], start: usize, len: usize) -> u64 {
+ debug_assert!(len < 8);
+ let mut i = 0; // current byte index (from LSB) in the output u64
+ let mut out = 0;
+ if i + 3 < len {
+ out = load_int_le!(buf, start + i, u32) as u64;
+ i += 4;
+ }
+ if i + 1 < len {
+ out |= (load_int_le!(buf, start + i, u16) as u64) << (i * 8);
+ i += 2
+ }
+ if i < len {
+ out |= (*buf.get_unchecked(start + i) as u64) << (i * 8);
+ i += 1;
+ }
+ debug_assert_eq!(i, len);
+ out
+}
+
+
+impl SipHasher128 {
+ #[inline]
+ pub fn new_with_keys(key0: u64, key1: u64) -> SipHasher128 {
+ let mut state = SipHasher128 {
+ k0: key0,
+ k1: key1,
+ length: 0,
+ state: State {
+ v0: 0,
+ v1: 0,
+ v2: 0,
+ v3: 0,
+ },
+ tail: 0,
+ ntail: 0,
+ };
+ state.reset();
+ state
+ }
+
+ #[inline]
+ fn reset(&mut self) {
+ self.length = 0;
+ self.state.v0 = self.k0 ^ 0x736f6d6570736575;
+ self.state.v1 = self.k1 ^ 0x646f72616e646f6d;
+ self.state.v2 = self.k0 ^ 0x6c7967656e657261;
+ self.state.v3 = self.k1 ^ 0x7465646279746573;
+ self.ntail = 0;
+
+ // This is only done in the 128 bit version:
+ self.state.v1 ^= 0xee;
+ }
+
+ // Specialized write function that is only valid for buffers with len <= 8.
+ // It's used to force inlining of write_u8 and write_usize, those would normally be inlined
+ // except for composite types (that includes slices and str hashing because of delimiter).
+ // Without this extra push the compiler is very reluctant to inline delimiter writes,
+ // degrading performance substantially for the most common use cases.
+ #[inline]
+ fn short_write(&mut self, msg: &[u8]) {
+ debug_assert!(msg.len() <= 8);
+ let length = msg.len();
+ self.length += length;
+
+ let needed = 8 - self.ntail;
+ let fill = cmp::min(length, needed);
+ if fill == 8 {
+ self.tail = unsafe { load_int_le!(msg, 0, u64) };
+ } else {
+ self.tail |= unsafe { u8to64_le(msg, 0, fill) } << (8 * self.ntail);
+ if length < needed {
+ self.ntail += length;
+ return;
+ }
+ }
+ self.state.v3 ^= self.tail;
+ Sip24Rounds::c_rounds(&mut self.state);
+ self.state.v0 ^= self.tail;
+
+ // Buffered tail is now flushed, process new input.
+ self.ntail = length - needed;
+ self.tail = unsafe { u8to64_le(msg, needed, self.ntail) };
+ }
+
+ #[inline(always)]
+ fn short_write_gen<T>(&mut self, x: T) {
+ let bytes = unsafe {
+ slice::from_raw_parts(&x as *const T as *const u8, mem::size_of::<T>())
+ };
+ self.short_write(bytes);
+ }
+
+ #[inline]
+ pub fn finish128(mut self) -> (u64, u64) {
+ let b: u64 = ((self.length as u64 & 0xff) << 56) | self.tail;
+
+ self.state.v3 ^= b;
+ Sip24Rounds::c_rounds(&mut self.state);
+ self.state.v0 ^= b;
+
+ self.state.v2 ^= 0xee;
+ Sip24Rounds::d_rounds(&mut self.state);
+ let _0 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3;
+
+ self.state.v1 ^= 0xdd;
+ Sip24Rounds::d_rounds(&mut self.state);
+ let _1 = self.state.v0 ^ self.state.v1 ^ self.state.v2 ^ self.state.v3;
+ (_0, _1)
+ }
+}
+
+impl Hasher for SipHasher128 {
+ #[inline]
+ fn write_u8(&mut self, i: u8) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write_u16(&mut self, i: u16) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write_u32(&mut self, i: u32) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write_u64(&mut self, i: u64) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write_usize(&mut self, i: usize) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write_i8(&mut self, i: i8) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write_i16(&mut self, i: i16) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write_i32(&mut self, i: i32) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write_i64(&mut self, i: i64) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write_isize(&mut self, i: isize) {
+ self.short_write_gen(i);
+ }
+
+ #[inline]
+ fn write(&mut self, msg: &[u8]) {
+ let length = msg.len();
+ self.length += length;
+
+ let mut needed = 0;
+
+ if self.ntail != 0 {
+ needed = 8 - self.ntail;
+ self.tail |= unsafe { u8to64_le(msg, 0, cmp::min(length, needed)) } << 8 * self.ntail;
+ if length < needed {
+ self.ntail += length;
+ return
+ } else {
+ self.state.v3 ^= self.tail;
+ Sip24Rounds::c_rounds(&mut self.state);
+ self.state.v0 ^= self.tail;
+ self.ntail = 0;
+ }
+ }
+
+ // Buffered tail is now flushed, process new input.
+ let len = length - needed;
+ let left = len & 0x7;
+
+ let mut i = needed;
+ while i < len - left {
+ let mi = unsafe { load_int_le!(msg, i, u64) };
+
+ self.state.v3 ^= mi;
+ Sip24Rounds::c_rounds(&mut self.state);
+ self.state.v0 ^= mi;
+
+ i += 8;
+ }
+
+ self.tail = unsafe { u8to64_le(msg, i, left) };
+ self.ntail = left;
+ }
+
+ fn finish(&self) -> u64 {
+ panic!("SipHasher128 cannot provide valid 64 bit hashes")
+ }
+}
+
+#[derive(Debug, Clone, Default)]
+struct Sip24Rounds;
+
+impl Sip24Rounds {
+ #[inline]
+ fn c_rounds(state: &mut State) {
+ compress!(state);
+ compress!(state);
+ }
+
+ #[inline]
+ fn d_rounds(state: &mut State) {
+ compress!(state);
+ compress!(state);
+ compress!(state);
+ compress!(state);
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use std::hash::{Hash, Hasher};
+ use std::{slice, mem};
+ use super::SipHasher128;
+
+ // Hash just the bytes of the slice, without length prefix
+ struct Bytes<'a>(&'a [u8]);
+
+ impl<'a> Hash for Bytes<'a> {
+ #[allow(unused_must_use)]
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ for byte in self.0 {
+ state.write_u8(*byte);
+ }
+ }
+ }
+
+ fn hash_with<T: Hash>(mut st: SipHasher128, x: &T) -> (u64, u64) {
+ x.hash(&mut st);
+ st.finish128()
+ }
+
+ fn hash<T: Hash>(x: &T) -> (u64, u64) {
+ hash_with(SipHasher128::new_with_keys(0, 0), x)
+ }
+
+ const TEST_VECTOR : [[u8; 16]; 64] = [
+ [0xa3,0x81,0x7f,0x04,0xba,0x25,0xa8,0xe6,0x6d,0xf6,0x72,0x14,0xc7,0x55,0x02,0x93],
+ [0xda,0x87,0xc1,0xd8,0x6b,0x99,0xaf,0x44,0x34,0x76,0x59,0x11,0x9b,0x22,0xfc,0x45],
+ [0x81,0x77,0x22,0x8d,0xa4,0xa4,0x5d,0xc7,0xfc,0xa3,0x8b,0xde,0xf6,0x0a,0xff,0xe4],
+ [0x9c,0x70,0xb6,0x0c,0x52,0x67,0xa9,0x4e,0x5f,0x33,0xb6,0xb0,0x29,0x85,0xed,0x51],
+ [0xf8,0x81,0x64,0xc1,0x2d,0x9c,0x8f,0xaf,0x7d,0x0f,0x6e,0x7c,0x7b,0xcd,0x55,0x79],
+ [0x13,0x68,0x87,0x59,0x80,0x77,0x6f,0x88,0x54,0x52,0x7a,0x07,0x69,0x0e,0x96,0x27],
+ [0x14,0xee,0xca,0x33,0x8b,0x20,0x86,0x13,0x48,0x5e,0xa0,0x30,0x8f,0xd7,0xa1,0x5e],
+ [0xa1,0xf1,0xeb,0xbe,0xd8,0xdb,0xc1,0x53,0xc0,0xb8,0x4a,0xa6,0x1f,0xf0,0x82,0x39],
+ [0x3b,0x62,0xa9,0xba,0x62,0x58,0xf5,0x61,0x0f,0x83,0xe2,0x64,0xf3,0x14,0x97,0xb4],
+ [0x26,0x44,0x99,0x06,0x0a,0xd9,0xba,0xab,0xc4,0x7f,0x8b,0x02,0xbb,0x6d,0x71,0xed],
+ [0x00,0x11,0x0d,0xc3,0x78,0x14,0x69,0x56,0xc9,0x54,0x47,0xd3,0xf3,0xd0,0xfb,0xba],
+ [0x01,0x51,0xc5,0x68,0x38,0x6b,0x66,0x77,0xa2,0xb4,0xdc,0x6f,0x81,0xe5,0xdc,0x18],
+ [0xd6,0x26,0xb2,0x66,0x90,0x5e,0xf3,0x58,0x82,0x63,0x4d,0xf6,0x85,0x32,0xc1,0x25],
+ [0x98,0x69,0xe2,0x47,0xe9,0xc0,0x8b,0x10,0xd0,0x29,0x93,0x4f,0xc4,0xb9,0x52,0xf7],
+ [0x31,0xfc,0xef,0xac,0x66,0xd7,0xde,0x9c,0x7e,0xc7,0x48,0x5f,0xe4,0x49,0x49,0x02],
+ [0x54,0x93,0xe9,0x99,0x33,0xb0,0xa8,0x11,0x7e,0x08,0xec,0x0f,0x97,0xcf,0xc3,0xd9],
+ [0x6e,0xe2,0xa4,0xca,0x67,0xb0,0x54,0xbb,0xfd,0x33,0x15,0xbf,0x85,0x23,0x05,0x77],
+ [0x47,0x3d,0x06,0xe8,0x73,0x8d,0xb8,0x98,0x54,0xc0,0x66,0xc4,0x7a,0xe4,0x77,0x40],
+ [0xa4,0x26,0xe5,0xe4,0x23,0xbf,0x48,0x85,0x29,0x4d,0xa4,0x81,0xfe,0xae,0xf7,0x23],
+ [0x78,0x01,0x77,0x31,0xcf,0x65,0xfa,0xb0,0x74,0xd5,0x20,0x89,0x52,0x51,0x2e,0xb1],
+ [0x9e,0x25,0xfc,0x83,0x3f,0x22,0x90,0x73,0x3e,0x93,0x44,0xa5,0xe8,0x38,0x39,0xeb],
+ [0x56,0x8e,0x49,0x5a,0xbe,0x52,0x5a,0x21,0x8a,0x22,0x14,0xcd,0x3e,0x07,0x1d,0x12],
+ [0x4a,0x29,0xb5,0x45,0x52,0xd1,0x6b,0x9a,0x46,0x9c,0x10,0x52,0x8e,0xff,0x0a,0xae],
+ [0xc9,0xd1,0x84,0xdd,0xd5,0xa9,0xf5,0xe0,0xcf,0x8c,0xe2,0x9a,0x9a,0xbf,0x69,0x1c],
+ [0x2d,0xb4,0x79,0xae,0x78,0xbd,0x50,0xd8,0x88,0x2a,0x8a,0x17,0x8a,0x61,0x32,0xad],
+ [0x8e,0xce,0x5f,0x04,0x2d,0x5e,0x44,0x7b,0x50,0x51,0xb9,0xea,0xcb,0x8d,0x8f,0x6f],
+ [0x9c,0x0b,0x53,0xb4,0xb3,0xc3,0x07,0xe8,0x7e,0xae,0xe0,0x86,0x78,0x14,0x1f,0x66],
+ [0xab,0xf2,0x48,0xaf,0x69,0xa6,0xea,0xe4,0xbf,0xd3,0xeb,0x2f,0x12,0x9e,0xeb,0x94],
+ [0x06,0x64,0xda,0x16,0x68,0x57,0x4b,0x88,0xb9,0x35,0xf3,0x02,0x73,0x58,0xae,0xf4],
+ [0xaa,0x4b,0x9d,0xc4,0xbf,0x33,0x7d,0xe9,0x0c,0xd4,0xfd,0x3c,0x46,0x7c,0x6a,0xb7],
+ [0xea,0x5c,0x7f,0x47,0x1f,0xaf,0x6b,0xde,0x2b,0x1a,0xd7,0xd4,0x68,0x6d,0x22,0x87],
+ [0x29,0x39,0xb0,0x18,0x32,0x23,0xfa,0xfc,0x17,0x23,0xde,0x4f,0x52,0xc4,0x3d,0x35],
+ [0x7c,0x39,0x56,0xca,0x5e,0xea,0xfc,0x3e,0x36,0x3e,0x9d,0x55,0x65,0x46,0xeb,0x68],
+ [0x77,0xc6,0x07,0x71,0x46,0xf0,0x1c,0x32,0xb6,0xb6,0x9d,0x5f,0x4e,0xa9,0xff,0xcf],
+ [0x37,0xa6,0x98,0x6c,0xb8,0x84,0x7e,0xdf,0x09,0x25,0xf0,0xf1,0x30,0x9b,0x54,0xde],
+ [0xa7,0x05,0xf0,0xe6,0x9d,0xa9,0xa8,0xf9,0x07,0x24,0x1a,0x2e,0x92,0x3c,0x8c,0xc8],
+ [0x3d,0xc4,0x7d,0x1f,0x29,0xc4,0x48,0x46,0x1e,0x9e,0x76,0xed,0x90,0x4f,0x67,0x11],
+ [0x0d,0x62,0xbf,0x01,0xe6,0xfc,0x0e,0x1a,0x0d,0x3c,0x47,0x51,0xc5,0xd3,0x69,0x2b],
+ [0x8c,0x03,0x46,0x8b,0xca,0x7c,0x66,0x9e,0xe4,0xfd,0x5e,0x08,0x4b,0xbe,0xe7,0xb5],
+ [0x52,0x8a,0x5b,0xb9,0x3b,0xaf,0x2c,0x9c,0x44,0x73,0xcc,0xe5,0xd0,0xd2,0x2b,0xd9],
+ [0xdf,0x6a,0x30,0x1e,0x95,0xc9,0x5d,0xad,0x97,0xae,0x0c,0xc8,0xc6,0x91,0x3b,0xd8],
+ [0x80,0x11,0x89,0x90,0x2c,0x85,0x7f,0x39,0xe7,0x35,0x91,0x28,0x5e,0x70,0xb6,0xdb],
+ [0xe6,0x17,0x34,0x6a,0xc9,0xc2,0x31,0xbb,0x36,0x50,0xae,0x34,0xcc,0xca,0x0c,0x5b],
+ [0x27,0xd9,0x34,0x37,0xef,0xb7,0x21,0xaa,0x40,0x18,0x21,0xdc,0xec,0x5a,0xdf,0x89],
+ [0x89,0x23,0x7d,0x9d,0xed,0x9c,0x5e,0x78,0xd8,0xb1,0xc9,0xb1,0x66,0xcc,0x73,0x42],
+ [0x4a,0x6d,0x80,0x91,0xbf,0x5e,0x7d,0x65,0x11,0x89,0xfa,0x94,0xa2,0x50,0xb1,0x4c],
+ [0x0e,0x33,0xf9,0x60,0x55,0xe7,0xae,0x89,0x3f,0xfc,0x0e,0x3d,0xcf,0x49,0x29,0x02],
+ [0xe6,0x1c,0x43,0x2b,0x72,0x0b,0x19,0xd1,0x8e,0xc8,0xd8,0x4b,0xdc,0x63,0x15,0x1b],
+ [0xf7,0xe5,0xae,0xf5,0x49,0xf7,0x82,0xcf,0x37,0x90,0x55,0xa6,0x08,0x26,0x9b,0x16],
+ [0x43,0x8d,0x03,0x0f,0xd0,0xb7,0xa5,0x4f,0xa8,0x37,0xf2,0xad,0x20,0x1a,0x64,0x03],
+ [0xa5,0x90,0xd3,0xee,0x4f,0xbf,0x04,0xe3,0x24,0x7e,0x0d,0x27,0xf2,0x86,0x42,0x3f],
+ [0x5f,0xe2,0xc1,0xa1,0x72,0xfe,0x93,0xc4,0xb1,0x5c,0xd3,0x7c,0xae,0xf9,0xf5,0x38],
+ [0x2c,0x97,0x32,0x5c,0xbd,0x06,0xb3,0x6e,0xb2,0x13,0x3d,0xd0,0x8b,0x3a,0x01,0x7c],
+ [0x92,0xc8,0x14,0x22,0x7a,0x6b,0xca,0x94,0x9f,0xf0,0x65,0x9f,0x00,0x2a,0xd3,0x9e],
+ [0xdc,0xe8,0x50,0x11,0x0b,0xd8,0x32,0x8c,0xfb,0xd5,0x08,0x41,0xd6,0x91,0x1d,0x87],
+ [0x67,0xf1,0x49,0x84,0xc7,0xda,0x79,0x12,0x48,0xe3,0x2b,0xb5,0x92,0x25,0x83,0xda],
+ [0x19,0x38,0xf2,0xcf,0x72,0xd5,0x4e,0xe9,0x7e,0x94,0x16,0x6f,0xa9,0x1d,0x2a,0x36],
+ [0x74,0x48,0x1e,0x96,0x46,0xed,0x49,0xfe,0x0f,0x62,0x24,0x30,0x16,0x04,0x69,0x8e],
+ [0x57,0xfc,0xa5,0xde,0x98,0xa9,0xd6,0xd8,0x00,0x64,0x38,0xd0,0x58,0x3d,0x8a,0x1d],
+ [0x9f,0xec,0xde,0x1c,0xef,0xdc,0x1c,0xbe,0xd4,0x76,0x36,0x74,0xd9,0x57,0x53,0x59],
+ [0xe3,0x04,0x0c,0x00,0xeb,0x28,0xf1,0x53,0x66,0xca,0x73,0xcb,0xd8,0x72,0xe7,0x40],
+ [0x76,0x97,0x00,0x9a,0x6a,0x83,0x1d,0xfe,0xcc,0xa9,0x1c,0x59,0x93,0x67,0x0f,0x7a],
+ [0x58,0x53,0x54,0x23,0x21,0xf5,0x67,0xa0,0x05,0xd5,0x47,0xa4,0xf0,0x47,0x59,0xbd],
+ [0x51,0x50,0xd1,0x77,0x2f,0x50,0x83,0x4a,0x50,0x3e,0x06,0x9a,0x97,0x3f,0xbd,0x7c],
+ ];
+
+ // Test vector from reference implementation
+ #[test]
+ fn test_siphash_2_4_test_vector() {
+ let k0 = 0x_07_06_05_04_03_02_01_00;
+ let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08;
+
+ let mut input: Vec<u8> = Vec::new();
+
+ for i in 0 .. 64 {
+ let out = hash_with(SipHasher128::new_with_keys(k0, k1),
+ &Bytes(&input[..]));
+ let expected = (
+ ((TEST_VECTOR[i][0] as u64) << 0) |
+ ((TEST_VECTOR[i][1] as u64) << 8) |
+ ((TEST_VECTOR[i][2] as u64) << 16) |
+ ((TEST_VECTOR[i][3] as u64) << 24) |
+ ((TEST_VECTOR[i][4] as u64) << 32) |
+ ((TEST_VECTOR[i][5] as u64) << 40) |
+ ((TEST_VECTOR[i][6] as u64) << 48) |
+ ((TEST_VECTOR[i][7] as u64) << 56),
+
+ ((TEST_VECTOR[i][8] as u64) << 0) |
+ ((TEST_VECTOR[i][9] as u64) << 8) |
+ ((TEST_VECTOR[i][10] as u64) << 16) |
+ ((TEST_VECTOR[i][11] as u64) << 24) |
+ ((TEST_VECTOR[i][12] as u64) << 32) |
+ ((TEST_VECTOR[i][13] as u64) << 40) |
+ ((TEST_VECTOR[i][14] as u64) << 48) |
+ ((TEST_VECTOR[i][15] as u64) << 56),
+ );
+
+ assert_eq!(out, expected);
+ input.push(i as u8);
+ }
+ }
+
+ #[test] #[cfg(target_arch = "arm")]
+ fn test_hash_usize() {
+ let val = 0xdeadbeef_deadbeef_u64;
+ assert!(hash(&(val as u64)) != hash(&(val as usize)));
+ assert_eq!(hash(&(val as u32)), hash(&(val as usize)));
+ }
+ #[test] #[cfg(target_arch = "x86_64")]
+ fn test_hash_usize() {
+ let val = 0xdeadbeef_deadbeef_u64;
+ assert_eq!(hash(&(val as u64)), hash(&(val as usize)));
+ assert!(hash(&(val as u32)) != hash(&(val as usize)));
+ }
+ #[test] #[cfg(target_arch = "x86")]
+ fn test_hash_usize() {
+ let val = 0xdeadbeef_deadbeef_u64;
+ assert!(hash(&(val as u64)) != hash(&(val as usize)));
+ assert_eq!(hash(&(val as u32)), hash(&(val as usize)));
+ }
+
+ #[test]
+ fn test_hash_idempotent() {
+ let val64 = 0xdeadbeef_deadbeef_u64;
+ assert_eq!(hash(&val64), hash(&val64));
+ let val32 = 0xdeadbeef_u32;
+ assert_eq!(hash(&val32), hash(&val32));
+ }
+
+ #[test]
+ fn test_hash_no_bytes_dropped_64() {
+ let val = 0xdeadbeef_deadbeef_u64;
+
+ assert!(hash(&val) != hash(&zero_byte(val, 0)));
+ assert!(hash(&val) != hash(&zero_byte(val, 1)));
+ assert!(hash(&val) != hash(&zero_byte(val, 2)));
+ assert!(hash(&val) != hash(&zero_byte(val, 3)));
+ assert!(hash(&val) != hash(&zero_byte(val, 4)));
+ assert!(hash(&val) != hash(&zero_byte(val, 5)));
+ assert!(hash(&val) != hash(&zero_byte(val, 6)));
+ assert!(hash(&val) != hash(&zero_byte(val, 7)));
+
+ fn zero_byte(val: u64, byte: usize) -> u64 {
+ assert!(byte < 8);
+ val & !(0xff << (byte * 8))
+ }
+ }
+
+ #[test]
+ fn test_hash_no_bytes_dropped_32() {
+ let val = 0xdeadbeef_u32;
+
+ assert!(hash(&val) != hash(&zero_byte(val, 0)));
+ assert!(hash(&val) != hash(&zero_byte(val, 1)));
+ assert!(hash(&val) != hash(&zero_byte(val, 2)));
+ assert!(hash(&val) != hash(&zero_byte(val, 3)));
+
+ fn zero_byte(val: u32, byte: usize) -> u32 {
+ assert!(byte < 4);
+ val & !(0xff << (byte * 8))
+ }
+ }
+
+ #[test]
+ fn test_hash_no_concat_alias() {
+ let s = ("aa", "bb");
+ let t = ("aabb", "");
+ let u = ("a", "abb");
+
+ assert!(s != t && t != u);
+ assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u));
+
+ let u = [1, 0, 0, 0];
+ let v = (&u[..1], &u[1..3], &u[3..]);
+ let w = (&u[..], &u[4..4], &u[4..4]);
+
+ assert!(v != w);
+ assert!(hash(&v) != hash(&w));
+ }
+
+ #[test]
+ fn test_write_short_works() {
+ let test_usize = 0xd0c0b0a0usize;
+ let mut h1 = SipHasher128::new_with_keys(0, 0);
+ h1.write_usize(test_usize);
+ h1.write(b"bytes");
+ h1.write(b"string");
+ h1.write_u8(0xFFu8);
+ h1.write_u8(0x01u8);
+ let mut h2 = SipHasher128::new_with_keys(0, 0);
+ h2.write(unsafe {
+ slice::from_raw_parts(&test_usize as *const _ as *const u8,
+ mem::size_of::<usize>())
+ });
+ h2.write(b"bytes");
+ h2.write(b"string");
+ h2.write(&[0xFFu8, 0x01u8]);
+ assert_eq!(h1.finish128(), h2.finish128());
+ }
+
+}
use std::hash::{Hash, Hasher, BuildHasher};
use std::marker::PhantomData;
use std::mem;
-use blake2b::Blake2bHasher;
-use rustc_serialize::leb128;
-
-fn write_unsigned_leb128_to_buf(buf: &mut [u8; 16], value: u64) -> usize {
- leb128::write_unsigned_leb128_to(value as u128, |i, v| buf[i] = v)
-}
-
-fn write_signed_leb128_to_buf(buf: &mut [u8; 16], value: i64) -> usize {
- leb128::write_signed_leb128_to(value as i128, |i, v| buf[i] = v)
-}
+use sip128::SipHasher128;
/// When hashing something that ends up affecting properties like symbol names. We
/// want these symbol names to be calculated independent of other factors like
/// and allows for variable output lengths through its type
/// parameter.
pub struct StableHasher<W> {
- state: Blake2bHasher,
+ state: SipHasher128,
bytes_hashed: u64,
width: PhantomData<W>,
}
impl<W: StableHasherResult> StableHasher<W> {
pub fn new() -> Self {
StableHasher {
- state: Blake2bHasher::new(mem::size_of::<W>(), &[]),
+ state: SipHasher128::new_with_keys(0, 0),
bytes_hashed: 0,
width: PhantomData,
}
}
}
-impl StableHasherResult for [u8; 20] {
- fn finish(mut hasher: StableHasher<Self>) -> Self {
- let mut result: [u8; 20] = [0; 20];
- result.copy_from_slice(hasher.state.finalize());
- result
- }
-}
-
impl StableHasherResult for u128 {
- fn finish(mut hasher: StableHasher<Self>) -> Self {
- let hash_bytes: &[u8] = hasher.finalize();
- assert!(hash_bytes.len() >= mem::size_of::<u128>());
-
- unsafe {
- ::std::ptr::read_unaligned(hash_bytes.as_ptr() as *const u128)
- }
+ fn finish(hasher: StableHasher<Self>) -> Self {
+ let (_0, _1) = hasher.finalize();
+ (_0 as u128) | ((_1 as u128) << 64)
}
}
impl StableHasherResult for u64 {
- fn finish(mut hasher: StableHasher<Self>) -> Self {
- hasher.state.finalize();
- hasher.state.finish()
+ fn finish(hasher: StableHasher<Self>) -> Self {
+ hasher.finalize().0
}
}
impl<W> StableHasher<W> {
#[inline]
- pub fn finalize(&mut self) -> &[u8] {
- self.state.finalize()
+ pub fn finalize(self) -> (u64, u64) {
+ self.state.finish128()
}
#[inline]
pub fn bytes_hashed(&self) -> u64 {
self.bytes_hashed
}
-
- #[inline]
- fn write_uleb128(&mut self, value: u64) {
- let mut buf = [0; 16];
- let len = write_unsigned_leb128_to_buf(&mut buf, value);
- self.state.write(&buf[..len]);
- self.bytes_hashed += len as u64;
- }
-
- #[inline]
- fn write_ileb128(&mut self, value: i64) {
- let mut buf = [0; 16];
- let len = write_signed_leb128_to_buf(&mut buf, value);
- self.state.write(&buf[..len]);
- self.bytes_hashed += len as u64;
- }
}
// For the non-u8 integer cases we leb128 encode them first. Because small
// bytes hashed, which is good because blake2b is expensive.
impl<W> Hasher for StableHasher<W> {
fn finish(&self) -> u64 {
- panic!("use StableHasher::finish instead");
+ panic!("use StableHasher::finalize instead");
}
#[inline]
#[inline]
fn write_u16(&mut self, i: u16) {
- self.write_uleb128(i as u64);
+ self.state.write_u16(i.to_le());
+ self.bytes_hashed += 2;
}
#[inline]
fn write_u32(&mut self, i: u32) {
- self.write_uleb128(i as u64);
+ self.state.write_u32(i.to_le());
+ self.bytes_hashed += 4;
}
#[inline]
fn write_u64(&mut self, i: u64) {
- self.write_uleb128(i);
+ self.state.write_u64(i.to_le());
+ self.bytes_hashed += 8;
+ }
+
+ #[inline]
+ fn write_u128(&mut self, i: u128) {
+ self.state.write_u128(i.to_le());
+ self.bytes_hashed += 16;
}
#[inline]
fn write_usize(&mut self, i: usize) {
- self.write_uleb128(i as u64);
+ self.state.write_usize(i.to_le());
+ self.bytes_hashed += ::std::mem::size_of::<usize>() as u64;
}
#[inline]
#[inline]
fn write_i16(&mut self, i: i16) {
- self.write_ileb128(i as i64);
+ self.state.write_i16(i.to_le());
+ self.bytes_hashed += 2;
}
#[inline]
fn write_i32(&mut self, i: i32) {
- self.write_ileb128(i as i64);
+ self.state.write_i32(i.to_le());
+ self.bytes_hashed += 4;
}
#[inline]
fn write_i64(&mut self, i: i64) {
- self.write_ileb128(i);
+ self.state.write_i64(i.to_le());
+ self.bytes_hashed += 8;
+ }
+
+ #[inline]
+ fn write_i128(&mut self, i: i128) {
+ self.state.write_i128(i.to_le());
+ self.bytes_hashed += 16;
}
#[inline]
fn write_isize(&mut self, i: isize) {
- self.write_ileb128(i as i64);
+ self.state.write_isize(i.to_le());
+ self.bytes_hashed += ::std::mem::size_of::<isize>() as u64;
}
}
use rustc_privacy;
use rustc_plugin::registry::Registry;
use rustc_plugin as plugin;
-use rustc_passes::{ast_validation, no_asm, loops, consts, static_recursion, hir_stats};
+use rustc_passes::{self, ast_validation, no_asm, loops, consts, static_recursion, hir_stats};
use rustc_const_eval::{self, check_match};
use super::Compilation;
use ::DefaultTransCrate;
traits::provide(&mut local_providers);
reachable::provide(&mut local_providers);
rustc_const_eval::provide(&mut local_providers);
+ rustc_passes::provide(&mut local_providers);
middle::region::provide(&mut local_providers);
cstore::provide_local(&mut local_providers);
lint::provide(&mut local_providers);
use syntax::ast;
use syntax::attr;
use syntax::feature_gate::{AttributeGate, AttributeType, Stability, deprecated_attributes};
-use syntax_pos::{Span, SyntaxContext};
+use syntax_pos::{BytePos, Span, SyntaxContext};
use syntax::symbol::keywords;
use rustc::hir::{self, PatKind};
declare_lint! {
NON_SHORTHAND_FIELD_PATTERNS,
Warn,
- "using `Struct { x: x }` instead of `Struct { x }`"
+ "using `Struct { x: x }` instead of `Struct { x }` in a pattern"
}
#[derive(Copy, Clone)]
}
if let PatKind::Binding(_, _, ident, None) = fieldpat.node.pat.node {
if ident.node == fieldpat.node.name {
- cx.span_lint(NON_SHORTHAND_FIELD_PATTERNS,
+ let mut err = cx.struct_span_lint(NON_SHORTHAND_FIELD_PATTERNS,
fieldpat.span,
- &format!("the `{}:` in this pattern is redundant and can \
- be removed",
- ident.node))
+ &format!("the `{}:` in this pattern is redundant",
+ ident.node));
+ let subspan = cx.tcx.sess.codemap().span_through_char(fieldpat.span, ':');
+ err.span_suggestion_short(subspan,
+ "remove this",
+ format!("{}", ident.node));
+ err.emit();
}
}
}
let mut db = cx.struct_span_lint(UNCONDITIONAL_RECURSION,
sp,
"function cannot return without recurring");
- // FIXME #19668: these could be span_lint_note's instead of this manual guard.
// offer some help to the programmer.
for call in &self_call_spans {
db.span_note(*call, "recursive call site");
fn check_item(&mut self, cx: &LateContext, it: &hir::Item) {
match it.node {
hir::ItemFn(.., ref generics, _) => {
- if attr::contains_name(&it.attrs, "no_mangle") &&
- !attr::contains_name(&it.attrs, "linkage") {
+ if let Some(no_mangle_attr) = attr::find_by_name(&it.attrs, "no_mangle") {
+ if attr::contains_name(&it.attrs, "linkage") {
+ return;
+ }
if !cx.access_levels.is_reachable(it.id) {
- let msg = format!("function {} is marked #[no_mangle], but not exported",
- it.name);
- cx.span_lint(PRIVATE_NO_MANGLE_FNS, it.span, &msg);
+ let msg = "function is marked #[no_mangle], but not exported";
+ let mut err = cx.struct_span_lint(PRIVATE_NO_MANGLE_FNS, it.span, msg);
+ let insertion_span = it.span.with_hi(it.span.lo());
+ err.span_suggestion(insertion_span,
+ "try making it public",
+ "pub ".to_owned());
+ err.emit();
}
if generics.is_type_parameterized() {
- cx.span_lint(NO_MANGLE_GENERIC_ITEMS,
- it.span,
- "functions generic over types must be mangled");
+ let mut err = cx.struct_span_lint(NO_MANGLE_GENERIC_ITEMS,
+ it.span,
+ "functions generic over \
+ types must be mangled");
+ err.span_suggestion_short(no_mangle_attr.span,
+ "remove this attribute",
+ "".to_owned());
+ err.emit();
}
}
}
hir::ItemStatic(..) => {
if attr::contains_name(&it.attrs, "no_mangle") &&
!cx.access_levels.is_reachable(it.id) {
- let msg = format!("static {} is marked #[no_mangle], but not exported",
- it.name);
- cx.span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, &msg);
+ let msg = "static is marked #[no_mangle], but not exported";
+ let mut err = cx.struct_span_lint(PRIVATE_NO_MANGLE_STATICS, it.span, msg);
+ let insertion_span = it.span.with_hi(it.span.lo());
+ err.span_suggestion(insertion_span,
+ "try making it public",
+ "pub ".to_owned());
+ err.emit();
}
}
hir::ItemConst(..) => {
if attr::contains_name(&it.attrs, "no_mangle") {
// Const items do not refer to a particular location in memory, and therefore
// don't have anything to attach a symbol to
- let msg = "const items should never be #[no_mangle], consider instead using \
- `pub static`";
- cx.span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
+ let msg = "const items should never be #[no_mangle]";
+ let mut err = cx.struct_span_lint(NO_MANGLE_CONST_ITEMS, it.span, msg);
+ // `const` is 5 chars
+ let const_span = it.span.with_hi(BytePos(it.span.lo().0 + 5));
+ err.span_suggestion(const_span,
+ "try a static value",
+ "pub static".to_owned());
+ err.emit();
}
}
_ => {}
};
let lazy_body = self.lazy(body);
- let tables = self.tcx.body_tables(body_id);
+ let body_owner_def_id = self.tcx.hir.body_owner_def_id(body_id);
+ let tables = self.tcx.typeck_tables_of(body_owner_def_id);
let lazy_tables = self.lazy(tables);
let mut visitor = NestedBodyCollector {
let lazy_nested_bodies = self.lazy_seq_ref_from_slice(&visitor.bodies_found);
let rvalue_promotable_to_static =
- self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
+ self.tcx.const_is_rvalue_promotable_to_static(body_owner_def_id);
self.lazy(&Ast {
body: lazy_body,
use build::matches::{Binding, MatchPair, Candidate};
use hair::*;
use rustc::mir::*;
-use rustc_data_structures::fx::FxHashMap;
use std::mem;
if self.hir.tcx().sess.features.borrow().never_type {
let irrefutable = adt_def.variants.iter().enumerate().all(|(i, v)| {
i == variant_index || {
- let mut visited = FxHashMap::default();
- let node_set = v.uninhabited_from(&mut visited,
- self.hir.tcx(),
- substs,
- adt_def.adt_kind());
- !node_set.is_empty()
+ self.hir.tcx().is_variant_uninhabited_from_all_modules(v, substs)
}
});
if irrefutable {
of `x` when we set `y`. This is fundamental to Rust's ownership system: outside
of workarounds like `Rc`, a value cannot be owned by more than one variable.
-If we own the type, the easiest way to address this problem is to implement
-`Copy` and `Clone` on it, as shown below. This allows `y` to copy the
-information in `x`, while leaving the original version owned by `x`. Subsequent
-changes to `x` will not be reflected when accessing `y`.
+Sometimes we don't need to move the value. Using a reference, we can let another
+function borrow the value without changing its ownership. In the example below,
+we don't actually have to move our string to `calculate_length`, we can give it
+a reference to it with `&` instead.
+
+```
+fn main() {
+ let s1 = String::from("hello");
+
+ let len = calculate_length(&s1);
+
+ println!("The length of '{}' is {}.", s1, len);
+}
+
+fn calculate_length(s: &String) -> usize {
+ s.len()
+}
+```
+
+A mutable reference can be created with `&mut`.
+
+Sometimes we don't want a reference, but a duplicate. All types marked `Clone`
+can be duplicated by calling `.clone()`. Subsequent changes to a clone do not
+affect the original variable.
+
+Most types in the standard library are marked `Clone`. The example below
+demonstrates using `clone()` on a string. `s1` is first set to "many", and then
+copied to `s2`. Then the first character of `s1` is removed, without affecting
+`s2`. "any many" is printed to the console.
+
+```
+fn main() {
+ let mut s1 = String::from("many");
+ let s2 = s1.clone();
+ s1.remove(0);
+ println!("{} {}", s1, s2);
+}
+```
+
+If we control the definition of a type, we can implement `Clone` on it ourselves
+with `#[derive(Clone)]`.
+
+Some types have no ownership semantics at all and are trivial to duplicate. An
+example is `i32` and the other number types. We don't have to call `.clone()` to
+clone them, because they are marked `Copy` in addition to `Clone`. Implicit
+cloning is more convienient in this case. We can mark our own types `Copy` if
+all their members also are marked `Copy`.
+
+In the example below, we implement a `Point` type. Because it only stores two
+integers, we opt-out of ownership semantics with `Copy`. Then we can
+`let p2 = p1` without `p1` being moved.
```
#[derive(Copy, Clone)]
-struct MyStruct { s: u32 }
+struct Point { x: i32, y: i32 }
fn main() {
- let mut x = MyStruct{ s: 5u32 };
- let y = x;
- x.s = 6;
- println!("{}", x.s);
+ let mut p1 = Point{ x: -1, y: 2 };
+ let p2 = p1;
+ p1.x = 1;
+ println!("p1: {}, {}", p1.x, p1.y);
+ println!("p2: {}, {}", p2.x, p2.y);
}
```
use rustc::middle::mem_categorization::Categorization;
use rustc::mir::transform::MirSource;
use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::maps::{queries, Providers};
use rustc::ty::subst::Substs;
use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
-use rustc::util::nodemap::NodeSet;
+use rustc::util::nodemap::{ItemLocalMap, NodeSet};
use rustc::lint::builtin::CONST_ERR;
-
use rustc::hir::{self, PatKind, RangeEnd};
+use std::rc::Rc;
use syntax::ast;
use syntax_pos::{Span, DUMMY_SP};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use std::collections::hash_map::Entry;
use std::cmp::Ordering;
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ rvalue_promotable_map,
+ const_is_rvalue_promotable_to_static,
+ ..*providers
+ };
+}
+
+pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ for &body_id in &tcx.hir.krate().body_ids {
+ let def_id = tcx.hir.body_owner_def_id(body_id);
+ tcx.const_is_rvalue_promotable_to_static(def_id);
+ }
+ tcx.sess.abort_if_errors();
+}
+
+fn const_is_rvalue_promotable_to_static<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> bool
+{
+ assert!(def_id.is_local());
+
+ let node_id = tcx.hir.as_local_node_id(def_id)
+ .expect("rvalue_promotable_map invoked with non-local def-id");
+ let body_id = tcx.hir.body_owned_by(node_id);
+ let body_hir_id = tcx.hir.node_to_hir_id(body_id.node_id);
+ tcx.rvalue_promotable_map(def_id).contains_key(&body_hir_id.local_id)
+}
+
+fn rvalue_promotable_map<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> Rc<ItemLocalMap<bool>>
+{
+ let outer_def_id = tcx.closure_base_def_id(def_id);
+ if outer_def_id != def_id {
+ return tcx.rvalue_promotable_map(outer_def_id);
+ }
+
+ let mut visitor = CheckCrateVisitor {
+ tcx,
+ tables: &ty::TypeckTables::empty(None),
+ in_fn: false,
+ in_static: false,
+ promotable: false,
+ mut_rvalue_borrows: NodeSet(),
+ param_env: ty::ParamEnv::empty(Reveal::UserFacing),
+ identity_substs: Substs::empty(),
+ result_map: ItemLocalMap(),
+ };
+
+ // `def_id` should be a `Body` owner
+ let node_id = tcx.hir.as_local_node_id(def_id)
+ .expect("rvalue_promotable_map invoked with non-local def-id");
+ let body_id = tcx.hir.body_owned_by(node_id);
+ visitor.visit_nested_body(body_id);
+
+ Rc::new(visitor.result_map)
+}
+
struct CheckCrateVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
in_fn: bool,
param_env: ty::ParamEnv<'tcx>,
identity_substs: &'tcx Substs<'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
+ result_map: ItemLocalMap<bool>,
}
impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+ // note that we *do* visit nested bodies, because we override `visit_nested_body` below
NestedVisitorMap::None
}
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
- match self.tcx.rvalue_promotable_to_static.borrow_mut().entry(body_id.node_id) {
- Entry::Occupied(_) => return,
- Entry::Vacant(entry) => {
- // Prevent infinite recursion on re-entry.
- entry.insert(false);
- }
- }
-
let item_id = self.tcx.hir.body_owner(body_id);
let item_def_id = self.tcx.hir.local_def_id(item_id);
let tcx = self.tcx;
let param_env = self.param_env;
let region_scope_tree = self.tcx.region_scope_tree(item_def_id);
- euv::ExprUseVisitor::new(self, tcx, param_env, ®ion_scope_tree, self.tables)
+ euv::ExprUseVisitor::new(self, tcx, param_env, ®ion_scope_tree, self.tables, None)
.consume_body(body);
self.visit_body(body);
}
}
- self.tcx.rvalue_promotable_to_static.borrow_mut().insert(ex.id, self.promotable);
+ self.result_map.insert(ex.hir_id.local_id, self.promotable);
self.promotable &= outer;
}
}
let promotable = if v.tcx.trait_of_item(did).is_some() {
// Don't peek inside trait associated constants.
false
- } else if let Some(node_id) = v.tcx.hir.as_local_node_id(did) {
- match v.tcx.hir.maybe_body_owned_by(node_id) {
- Some(body) => {
- v.visit_nested_body(body);
- v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
- }
- None => false
- }
} else {
- v.tcx.const_is_rvalue_promotable_to_static(did)
+ queries::const_is_rvalue_promotable_to_static::try_get(v.tcx, e.span, did)
+ .unwrap_or_else(|mut err| {
+ // A cycle between constants ought to be reported elsewhere.
+ err.cancel();
+ v.tcx.sess.delay_span_bug(
+ e.span,
+ &format!("cycle encountered during const qualification: {:?}",
+ did));
+ false
+ })
};
// Just in case the type is more specific than the definition,
}
}
-pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- tcx.hir.krate().visit_all_item_likes(&mut CheckCrateVisitor {
- tcx,
- tables: &ty::TypeckTables::empty(None),
- in_fn: false,
- in_static: false,
- promotable: false,
- mut_rvalue_borrows: NodeSet(),
- param_env: ty::ParamEnv::empty(Reveal::UserFacing),
- identity_substs: Substs::empty(),
- }.as_deep_visitor());
- tcx.sess.abort_if_errors();
-}
-
impl<'a, 'gcx, 'tcx> euv::Delegate<'tcx> for CheckCrateVisitor<'a, 'gcx> {
fn consume(&mut self,
_consume_id: ast::NodeId,
extern crate syntax_pos;
extern crate rustc_errors as errors;
+use rustc::ty::maps::Providers;
+
mod diagnostics;
pub mod ast_validation;
pub mod static_recursion;
__build_diagnostic_array! { librustc_passes, DIAGNOSTICS }
+
+pub fn provide(providers: &mut Providers) {
+ consts::provide(providers);
+}
self
}
+ pub fn contains(&self, attr: ArgAttribute) -> bool {
+ self.regular.contains(attr)
+ }
+
pub fn apply_llfn(&self, idx: AttributePlace, llfn: ValueRef) {
unsafe {
self.regular.for_each_kind(|attr| attr.apply_llfn(idx, llfn));
use rustc::ty::subst::Substs;
use rustc::ty::util::TypeIdHasher;
use rustc::hir;
-use rustc_data_structures::ToHex;
+use rustc::ich::Fingerprint;
use {type_of, machine, monomorphize};
use common::{self, CrateContext};
use type_::Type;
// The hasher we are using to generate the UniqueTypeId. We want
// something that provides more than the 64 bits of the DefaultHasher.
-
- let mut type_id_hasher = TypeIdHasher::<[u8; 20]>::new(cx.tcx());
+ let mut type_id_hasher = TypeIdHasher::<Fingerprint>::new(cx.tcx());
type_id_hasher.visit_ty(type_);
-
let unique_type_id = type_id_hasher.finish().to_hex();
+
let key = self.unique_id_interner.intern(&unique_type_id);
self.type_to_unique_id.insert(type_, UniqueTypeId(key));
const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "vfp2\0", "vfp3\0", "vfp4\0"];
+const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0"];
+
const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
"sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
"ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
let whitelist = match &*sess.target.target.arch {
"arm" => ARM_WHITELIST,
+ "aarch64" => AARCH64_WHITELIST,
"x86" | "x86_64" => X86_WHITELIST,
"hexagon" => HEXAGON_WHITELIST,
"powerpc" | "powerpc64" => POWERPC_WHITELIST,
use common::{self, CrateContext, Funclet};
use debuginfo::{self, declare_local, VariableAccess, VariableKind, FunctionDebugContext};
use monomorphize::Instance;
-use abi::FnType;
+use abi::{ArgAttribute, FnType};
use type_of;
use syntax_pos::{DUMMY_SP, NO_EXPANSION, BytePos, Span};
None
};
+ let deref_op = unsafe {
+ [llvm::LLVMRustDIBuilderCreateOpDeref()]
+ };
+
mir.args_iter().enumerate().map(|(arg_index, local)| {
let arg_decl = &mir.local_decls[local];
let arg_ty = mircx.monomorphize(&arg_decl.ty);
let arg = &mircx.fn_ty.args[idx];
idx += 1;
- let llval = if arg.is_indirect() && bcx.sess().opts.debuginfo != FullDebugInfo {
+ let llval = if arg.is_indirect() {
// Don't copy an indirect argument to an alloca, the caller
- // already put it in a temporary alloca and gave it up, unless
- // we emit extra-debug-info, which requires local allocas :(.
+ // already put it in a temporary alloca and gave it up
// FIXME: lifetimes
if arg.pad.is_some() {
llarg_idx += 1;
llarg_idx += 1;
llarg
} else if !lvalue_locals.contains(local.index()) &&
- !arg.is_indirect() && arg.cast.is_none() &&
- arg_scope.is_none() {
+ arg.cast.is_none() && arg_scope.is_none() {
if arg.is_ignore() {
return LocalRef::new_operand(bcx.ccx, arg_ty);
}
arg_scope.map(|scope| {
// Is this a regular argument?
if arg_index > 0 || mir.upvar_decls.is_empty() {
+ // The Rust ABI passes indirect variables using a pointer and a manual copy, so we
+ // need to insert a deref here, but the C ABI uses a pointer and a copy using the
+ // byval attribute, for which LLVM does the deref itself, so we must not add it.
+ let variable_access = if arg.is_indirect() &&
+ !arg.attrs.contains(ArgAttribute::ByVal) {
+ VariableAccess::IndirectVariable {
+ alloca: llval,
+ address_operations: &deref_op,
+ }
+ } else {
+ VariableAccess::DirectVariable { alloca: llval }
+ };
+
declare_local(
bcx,
&mircx.debug_context,
arg_decl.name.unwrap_or(keywords::Invalid.name()),
arg_ty,
scope,
- VariableAccess::DirectVariable { alloca: llval },
+ variable_access,
VariableKind::ArgumentVariable(arg_index + 1),
DUMMY_SP
);
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::subst::{Subst, Substs};
use syntax::ast;
-use syntax::attr;
+use syntax::attr::{self, InlineAttr};
use syntax_pos::Span;
use syntax_pos::symbol::Symbol;
use type_of;
match *self.as_trans_item() {
TransItem::Fn(ref instance) => {
- if self.explicit_linkage(tcx).is_none() &&
- common::requests_inline(tcx, instance)
+ // If this function isn't inlined or otherwise has explicit
+ // linkage, then we'll be creating a globally shared version.
+ if self.explicit_linkage(tcx).is_some() ||
+ !common::requests_inline(tcx, instance)
{
- if inline_in_all_cgus {
- InstantiationMode::LocalCopy
- } else {
+ return InstantiationMode::GloballyShared { may_conflict: false }
+ }
+
+ // At this point we don't have explicit linkage and we're an
+ // inlined function. If we're inlining into all CGUs then we'll
+ // be creating a local copy per CGU
+ if inline_in_all_cgus {
+ return InstantiationMode::LocalCopy
+ }
+
+ // Finally, if this is `#[inline(always)]` we're sure to respect
+ // that with an inline copy per CGU, but otherwise we'll be
+ // creating one copy of this `#[inline]` function which may
+ // conflict with upstream crates as it could be an exported
+ // symbol.
+ let attrs = instance.def.attrs(tcx);
+ match attr::find_inline_attr(Some(tcx.sess.diagnostic()), &attrs) {
+ InlineAttr::Always => InstantiationMode::LocalCopy,
+ _ => {
InstantiationMode::GloballyShared { may_conflict: true }
}
- } else {
- InstantiationMode::GloballyShared { may_conflict: false }
}
}
TransItem::Static(..) => {
CoerceMany::with_coercion_sites(coerce_to_ty, tail_expr)
};
+ let prev_diverges = self.diverges.get();
let ctxt = BreakableCtxt {
coerce: Some(coerce),
may_break: false,
}
});
+ if ctxt.may_break {
+ // If we can break from the block, then the block's exit is always reachable
+ // (... as long as the entry is reachable) - regardless of the tail of the block.
+ self.diverges.set(prev_diverges);
+ }
+
let mut ty = ctxt.coerce.unwrap().complete(self);
if self.has_errors.get() || ty.references_error() {
// the type of the node expr.id here *before applying
// adjustments*.
//
- // FIXME(#6268) nested method calls requires that this rule change
+ // FIXME(https://github.com/rust-lang/rfcs/issues/811)
+ // nested method calls requires that this rule change
let ty0 = self.resolve_node_type(expr.hir_id);
self.type_must_outlive(infer::AddrOf(expr.span), ty0, expr_region);
intravisit::walk_expr(self, expr);
fn predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> ty::GenericPredicates<'tcx> {
- explicit_predicates_of(tcx, def_id)
+ let explicit = explicit_predicates_of(tcx, def_id);
+ ty::GenericPredicates {
+ parent: explicit.parent,
+ predicates: [&explicit.predicates[..], &tcx.inferred_outlives_of(def_id)[..]].concat()
+ }
}
fn explicit_predicates_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
E0588, // packed struct cannot transitively contain a `[repr(align)]` struct
E0592, // duplicate definitions with name `{}`
// E0613, // Removed (merged with E0609)
+ E0640, // infer outlives
E0627, // yield statement outside of generator literal
E0632, // cannot provide explicit type parameters when `impl Trait` is used in
// argument position.
- variance: variance inference
+- outlives: outlives inference
+
- check: walks over function bodies and type checks them, inferring types for
local variables, type parameters, etc as necessary.
mod constrained_type_params;
mod impl_wf_check;
mod coherence;
+mod outlives;
mod variance;
mod namespace;
coherence::provide(providers);
check::provide(providers);
variance::provide(providers);
+ outlives::provide(providers);
}
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
})?;
+ tcx.sess.track_errors(|| {
+ time(time_passes, "outlives testing", ||
+ outlives::test::test_inferred_outlives(tcx));
+ })?;
+
tcx.sess.track_errors(|| {
time(time_passes, "impl wf inference", ||
impl_wf_check::impl_wf_check(tcx));
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::hir::def_id::DefId;
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::maps::Providers;
+
+/// Code to write unit test for outlives.
+pub mod test;
+
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ inferred_outlives_of,
+ ..*providers
+ };
+}
+
+//todo
+fn inferred_outlives_of<'a, 'tcx>(_tcx: TyCtxt<'a, 'tcx, 'tcx>, _def_id: DefId)
+ -> Vec<ty::Predicate<'tcx>> {
+ Vec::new()
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::hir;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::ty::TyCtxt;
+
+pub fn test_inferred_outlives<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ tcx.hir.krate().visit_all_item_likes(&mut OutlivesTest { tcx });
+}
+
+struct OutlivesTest<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx> ItemLikeVisitor<'tcx> for OutlivesTest<'a, 'tcx> {
+ fn visit_item(&mut self, item: &'tcx hir::Item) {
+ let item_def_id = self.tcx.hir.local_def_id(item.id);
+
+ // For unit testing: check for a special "rustc_outlives"
+ // attribute and report an error with various results if found.
+ if self.tcx.has_attr(item_def_id, "rustc_outlives") {
+ let inferred_outlives_of = self.tcx.inferred_outlives_of(item_def_id);
+ span_err!(self.tcx.sess,
+ item.span,
+ E0640,
+ "{:?}",
+ inferred_outlives_of);
+ }
+ }
+
+ fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) { }
+ fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) { }
+}
if prim.is_some() {
break;
}
+ // FIXME: should warn on unknown primitives?
}
}
}
Slice,
Array,
Tuple,
+ Unit,
RawPointer,
Reference,
Fn,
Primitive(p) | BorrowedRef { type_: box Primitive(p), ..} => Some(p),
Slice(..) | BorrowedRef { type_: box Slice(..), .. } => Some(PrimitiveType::Slice),
Array(..) | BorrowedRef { type_: box Array(..), .. } => Some(PrimitiveType::Array),
- Tuple(..) => Some(PrimitiveType::Tuple),
+ Tuple(ref tys) => if tys.is_empty() {
+ Some(PrimitiveType::Unit)
+ } else {
+ Some(PrimitiveType::Tuple)
+ },
RawPointer(..) => Some(PrimitiveType::RawPointer),
BorrowedRef { type_: box Generic(..), .. } => Some(PrimitiveType::Reference),
BareFunction(..) => Some(PrimitiveType::Fn),
BorrowedRef { type_: box Generic(..), .. } =>
Primitive(PrimitiveType::Reference).def_id(),
BorrowedRef { ref type_, .. } => type_.def_id(),
- Tuple(..) => Primitive(PrimitiveType::Tuple).def_id(),
+ Tuple(ref tys) => if tys.is_empty() {
+ Primitive(PrimitiveType::Unit).def_id()
+ } else {
+ Primitive(PrimitiveType::Tuple).def_id()
+ },
BareFunction(..) => Primitive(PrimitiveType::Fn).def_id(),
Slice(..) => Primitive(PrimitiveType::Slice).def_id(),
Array(..) => Primitive(PrimitiveType::Array).def_id(),
"array" => Some(PrimitiveType::Array),
"slice" => Some(PrimitiveType::Slice),
"tuple" => Some(PrimitiveType::Tuple),
+ "unit" => Some(PrimitiveType::Unit),
"pointer" => Some(PrimitiveType::RawPointer),
"reference" => Some(PrimitiveType::Reference),
"fn" => Some(PrimitiveType::Fn),
Array => "array",
Slice => "slice",
Tuple => "tuple",
+ Unit => "unit",
RawPointer => "pointer",
Reference => "reference",
Fn => "fn",
Slice => tcx.lang_items().slice_impl(),
Array => tcx.lang_items().slice_impl(),
Tuple => None,
+ Unit => None,
RawPointer => tcx.lang_items().const_ptr_impl(),
Reference => None,
Fn => None,
}
clean::Tuple(ref typs) => {
match &typs[..] {
- &[] => primitive_link(f, PrimitiveType::Tuple, "()"),
+ &[] => primitive_link(f, PrimitiveType::Unit, "()"),
&[ref one] => {
primitive_link(f, PrimitiveType::Tuple, "(")?;
//carry f.alternate() into this display w/o branching manually
<dd>Move up in search results</dd>
<dt>↓</dt>
<dd>Move down in search results</dd>
+ <dt>↹</dt>
+ <dd>Switch tab</dd>
<dt>⏎</dt>
<dd>Go to active search result</dd>
<dt>+</dt>
prefix: &str,
scx: &SharedContext)
-> fmt::Result {
- // We only emit warnings if the user has opted-in to Pulldown rendering.
- let output = if render_type == RenderType::Pulldown {
- // Save the state of USED_ID_MAP so it only gets updated once even
- // though we're rendering twice.
- let orig_used_id_map = USED_ID_MAP.with(|map| map.borrow().clone());
- let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
- USED_ID_MAP.with(|map| *map.borrow_mut() = orig_used_id_map);
- let pulldown_output = format!("{}", Markdown(md_text, RenderType::Pulldown));
- let mut differences = html_diff::get_differences(&pulldown_output, &hoedown_output);
- differences.retain(|s| {
- match *s {
- html_diff::Difference::NodeText { ref elem_text,
- ref opposite_elem_text,
- .. }
- if elem_text.split_whitespace().eq(opposite_elem_text.split_whitespace()) => {
- false
- }
- _ => true,
+ // Save the state of USED_ID_MAP so it only gets updated once even
+ // though we're rendering twice.
+ let orig_used_id_map = USED_ID_MAP.with(|map| map.borrow().clone());
+ let hoedown_output = format!("{}", Markdown(md_text, RenderType::Hoedown));
+ USED_ID_MAP.with(|map| *map.borrow_mut() = orig_used_id_map);
+ let pulldown_output = format!("{}", Markdown(md_text, RenderType::Pulldown));
+ let mut differences = html_diff::get_differences(&pulldown_output, &hoedown_output);
+ differences.retain(|s| {
+ match *s {
+ html_diff::Difference::NodeText { ref elem_text,
+ ref opposite_elem_text,
+ .. }
+ if elem_text.split_whitespace().eq(opposite_elem_text.split_whitespace()) => {
+ false
}
- });
-
- if !differences.is_empty() {
- scx.markdown_warnings.borrow_mut().push((span, md_text.to_owned(), differences));
+ _ => true,
}
+ });
- pulldown_output
- } else {
- format!("{}", Markdown(md_text, RenderType::Hoedown))
- };
+ if !differences.is_empty() {
+ scx.markdown_warnings.borrow_mut().push((span, md_text.to_owned(), differences));
+ }
- write!(w, "<div class='docblock'>{}{}</div>", prefix, output)
+ write!(w, "<div class='docblock'>{}{}</div>",
+ prefix,
+ if render_type == RenderType::Pulldown { pulldown_output } else { hoedown_output })
}
fn document_short(w: &mut fmt::Formatter, item: &clean::Item, link: AssocItemLink,
"associatedconstant",
"union"];
+ // On the search screen, so you remain on the last tab you opened.
+ //
+ // 0 for "Types/modules"
+ // 1 for "As parameters"
+ // 2 for "As return value"
+ var currentTab = 0;
+
function hasClass(elem, className) {
if (elem && className && elem.className) {
var elemClass = elem.className;
return String.fromCharCode(c);
}
+ function displayHelp(display, ev) {
+ if (display === true) {
+ if (hasClass(help, "hidden")) {
+ ev.preventDefault();
+ removeClass(help, "hidden");
+ addClass(document.body, "blur");
+ }
+ } else if (!hasClass(help, "hidden")) {
+ ev.preventDefault();
+ addClass(help, "hidden");
+ removeClass(document.body, "blur");
+ }
+ }
+
function handleShortcut(ev) {
if (document.activeElement.tagName === "INPUT")
return;
case "Escape":
var search = document.getElementById("search");
if (!hasClass(help, "hidden")) {
- ev.preventDefault();
- addClass(help, "hidden");
- removeClass(document.body, "blur");
+ displayHelp(false, ev);
} else if (!hasClass(search, "hidden")) {
ev.preventDefault();
addClass(search, "hidden");
case "s":
case "S":
+ displayHelp(false, ev);
ev.preventDefault();
focusSearchBar();
break;
break;
case "?":
- if (ev.shiftKey && hasClass(help, "hidden")) {
- ev.preventDefault();
- removeClass(help, "hidden");
- addClass(document.body, "blur");
+ if (ev.shiftKey) {
+ displayHelp(true, ev);
}
break;
}
});
var search_input = document.getElementsByClassName('search-input')[0];
- search_input.onkeydown = null;
search_input.onkeydown = function(e) {
- var actives = [];
+ // "actives" references the currently highlighted item in each search tab.
+ // Each array in "actives" represents a tab.
+ var actives = [[], [], []];
+ // "current" is used to know which tab we're looking into.
+ var current = 0;
onEach(document.getElementsByClassName('search-results'), function(e) {
- onEach(document.getElementsByClassName('highlighted'), function(e) {
- actives.push(e);
+ onEach(e.getElementsByClassName('highlighted'), function(e) {
+ actives[current].push(e);
});
+ current += 1;
});
if (e.which === 38) { // up
- if (!actives.length || !actives[0].previousElementSibling) {
+ if (!actives[currentTab].length ||
+ !actives[currentTab][0].previousElementSibling) {
return;
}
- addClass(actives[0].previousElementSibling, 'highlighted');
- removeClass(actives[0], 'highlighted');
+ addClass(actives[currentTab][0].previousElementSibling, 'highlighted');
+ removeClass(actives[currentTab][0], 'highlighted');
} else if (e.which === 40) { // down
- if (!actives.length) {
+ if (!actives[currentTab].length) {
var results = document.getElementsByClassName('search-results');
if (results.length > 0) {
- var res = results[0].getElementsByClassName('result');
+ var res = results[currentTab].getElementsByClassName('result');
if (res.length > 0) {
addClass(res[0], 'highlighted');
}
}
- } else if (actives[0].nextElementSibling) {
- addClass(actives[0].nextElementSibling, 'highlighted');
- removeClass(actives[0], 'highlighted');
+ } else if (actives[currentTab][0].nextElementSibling) {
+ addClass(actives[currentTab][0].nextElementSibling, 'highlighted');
+ removeClass(actives[currentTab][0], 'highlighted');
}
} else if (e.which === 13) { // return
- if (actives.length) {
- document.location.href = actives[0].getElementsByTagName('a')[0].href;
+ if (actives[currentTab].length) {
+ document.location.href =
+ actives[currentTab][0].getElementsByTagName('a')[0].href;
+ }
+ } else if (e.which === 9) { // tab
+ if (e.shiftKey) {
+ printTab(currentTab > 0 ? currentTab - 1 : 2);
+ } else {
+ printTab(currentTab > 1 ? 0 : currentTab + 1);
}
- } else if (actives.length > 0) {
- removeClass(actives[0], 'highlighted');
+ e.preventDefault();
+ } else if (e.which === 16) { // shift
+ // Does nothing, it's just to avoid losing "focus" on the highlighted element.
+ } else if (actives[currentTab].length > 0) {
+ removeClass(actives[currentTab][0], 'highlighted');
}
};
}
var output = '';
if (array.length > 0) {
- output = `<table class="search-results"${extraStyle}>`;
+ output = '<table class="search-results"' + extraStyle + '>';
var shown = [];
array.forEach(function(item) {
});
output += '</table>';
} else {
- output = `<div class="search-failed"${extraStyle}>No results :(<br/>` +
+ output = '<div class="search-failed"' + extraStyle + '>No results :(<br/>' +
'Try on <a href="https://duckduckgo.com/?q=' +
encodeURIComponent('rust ' + query.query) +
'">DuckDuckGo</a>?</div>';
return output;
}
+ function makeTabHeader(tabNb, text) {
+ if (currentTab === tabNb) {
+ return '<div class="selected">' + text + '</div>';
+ }
+ return '<div>' + text + '</div>';
+ }
+
function showResults(results) {
var output, query = getQuery();
output = '<h1>Results for ' + escape(query.query) +
(query.type ? ' (type: ' + escape(query.type) + ')' : '') + '</h1>' +
'<div id="titles">' +
- '<div class="selected">Types/modules</div>' +
- '<div>As parameters</div>' +
- '<div>As return value</div></div><div id="results">';
+ makeTabHeader(0, "Types/modules") +
+ makeTabHeader(1, "As parameters") +
+ makeTabHeader(2, "As return value") +
+ '</div><div id="results">';
output += addTab(results['others'], query);
output += addTab(results['in_args'], query, false);
// In the search display, allows to switch between tabs.
function printTab(nb) {
+ if (nb === 0 || nb === 1 || nb === 2) {
+ currentTab = nb;
+ }
var nb_copy = nb;
onEach(document.getElementById('titles').childNodes, function(elem) {
if (nb_copy === 0) {
flex: 0 0 auto;
box-shadow: 0 0 6px rgba(0,0,0,.2);
width: 550px;
- height: 330px;
+ height: 354px;
border: 1px solid;
}
#help dt {
stable("no-default", |o| {
o.optflag("", "no-defaults", "don't run the default passes")
}),
+ stable("document-private-items", |o| {
+ o.optflag("", "document-private-items", "document private items")
+ }),
stable("test", |o| o.optflag("", "test", "run code examples as tests")),
stable("test-args", |o| {
o.optmulti("", "test-args", "arguments to pass to the test runner",
// Check for unstable options.
nightly_options::check_nightly_options(&matches, &opts());
+ // check for deprecated options
+ check_deprecated_options(&matches);
+
if matches.opt_present("h") || matches.opt_present("help") {
usage("rustdoc");
return 0;
let mut passes = matches.opt_strs("passes");
let mut plugins = matches.opt_strs("plugins");
+ // We hardcode in the passes here, as this is a new flag and we
+ // are generally deprecating passes.
+ if matches.opt_present("document-private-items") {
+ default_passes = false;
+
+ passes = vec![
+ String::from("strip-hidden"),
+ String::from("collapse-docs"),
+ String::from("unindent-comments"),
+ ];
+ }
+
// First, parse the crate and extract all relevant information.
let mut paths = SearchPaths::new();
for s in &matches.opt_strs("L") {
});
rx.recv().unwrap()
}
+
+/// Prints deprecation warnings for deprecated options
+fn check_deprecated_options(matches: &getopts::Matches) {
+ let deprecated_flags = [
+ "input-format",
+ "output-format",
+ "plugin-path",
+ "plugins",
+ "no-defaults",
+ "passes",
+ ];
+
+ for flag in deprecated_flags.into_iter() {
+ if matches.opt_present(flag) {
+ eprintln!("WARNING: the '{}' flag is considered deprecated", flag);
+ eprintln!("WARNING: please see https://github.com/rust-lang/rust/issues/44136");
+ }
+ }
+
+ if matches.opt_present("no-defaults") {
+ eprintln!("WARNING: (you may want to use --document-private-items)");
+ }
+}
/// Arrays of sizes from 0 to 32 (inclusive) implement the following traits if
/// the element type allows it:
///
-/// - [`Clone`][clone] (only if `T: `[`Copy`][copy])
/// - [`Debug`][debug]
/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`)
/// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord]
/// entirely different types. As a stopgap, trait implementations are
/// statically generated up to size 32.
///
-/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy]. This
-/// works because the [`Copy`][copy] trait is specially known to the compiler.
+/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy]
+/// and [`Clone`][clone] if the element type is [`Clone`][clone]. This works
+/// because [`Copy`][copy] and [`Clone`][clone] traits are specially known
+/// to the compiler.
///
/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
/// an array. Indeed, this provides most of the API for working with arrays.
/// Configuration for the child process's standard input (stdin) handle.
///
+ /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+ /// defaults to [`piped`] when used with `output`.
+ ///
+ /// [`inherit`]: struct.Stdio.html#method.inherit
+ /// [`piped`]: struct.Stdio.html#method.piped
+ ///
/// # Examples
///
/// Basic usage:
/// Configuration for the child process's standard output (stdout) handle.
///
+ /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+ /// defaults to [`piped`] when used with `output`.
+ ///
+ /// [`inherit`]: struct.Stdio.html#method.inherit
+ /// [`piped`]: struct.Stdio.html#method.piped
+ ///
/// # Examples
///
/// Basic usage:
/// Configuration for the child process's standard error (stderr) handle.
///
+ /// Defaults to [`inherit`] when used with `spawn` or `status`, and
+ /// defaults to [`piped`] when used with `output`.
+ ///
+ /// [`inherit`]: struct.Stdio.html#method.inherit
+ /// [`piped`]: struct.Stdio.html#method.piped
+ ///
/// # Examples
///
/// Basic usage:
/// to. For a directory, the structure specifies when the directory was
/// created.
///
- /// If the underlying filesystem does not support the last write time
- /// time, the returned value is 0.
+ /// If the underlying filesystem does not support the last write time,
+ /// the returned value is 0.
///
/// # Examples
///
///
/// Once the initialization expression succeeds, the key transitions to the
/// `Valid` state which will guarantee that future calls to [`with`] will
- /// succeed within the thread.
+ /// succeed within the thread. Some keys might skip the `Uninitialized`
+ /// state altogether and start in the `Valid` state as an optimization
+ /// (e.g. keys initialized with a constant expression), but no guarantees
+ /// are made.
///
/// When a thread exits, each key will be destroyed in turn, and as keys are
/// destroyed they will enter the `Destroyed` state just before the
}
}
+ /// Given a `Span`, try to get a shorter span ending just after the first
+ /// occurrence of `char` `c`.
+ pub fn span_through_char(&self, sp: Span, c: char) -> Span {
+ if let Ok(snippet) = self.span_to_snippet(sp) {
+ if let Some(offset) = snippet.find(c) {
+ return sp.with_hi(BytePos(sp.lo().0 + (offset + c.len_utf8()) as u32));
+ }
+ }
+ sp
+ }
+
pub fn def_span(&self, sp: Span) -> Span {
self.span_until_char(sp, '{')
}
node: StmtKind::Item(i),
},
None => {
- let unused_attrs = |attrs: &[_], s: &mut Self| {
+ let unused_attrs = |attrs: &[Attribute], s: &mut Self| {
if !attrs.is_empty() {
if s.prev_token_kind == PrevTokenKind::DocComment {
s.span_fatal_err(s.prev_span, Error::UselessDocComment).emit();
- } else {
+ } else if attrs.iter().any(|a| a.style == AttrStyle::Outer) {
s.span_err(s.span, "expected statement after outer attribute");
}
}
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#if LLVM_VERSION_GE(4, 0)
-#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/FunctionImport.h"
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
#include "llvm/LTO/LTO.h"
+#if LLVM_VERSION_LE(4, 0)
+#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
+#endif
#endif
#include "llvm-c/Transforms/PassManagerBuilder.h"
return;
Preserved.insert(GUID);
+#if LLVM_VERSION_GE(5, 0)
+ auto Info = Index.getValueInfo(GUID);
+ if (!Info) {
+ return;
+ }
+ for (auto &Summary : Info.getSummaryList()) {
+ for (auto &Ref : Summary->refs()) {
+ addPreservedGUID(Index, Preserved, Ref.getGUID());
+ }
+
+ GlobalValueSummary *GVSummary = Summary.get();
+ if (isa<FunctionSummary>(GVSummary)) {
+ auto *FS = cast<FunctionSummary>(GVSummary);
+ for (auto &Call: FS->calls()) {
+ addPreservedGUID(Index, Preserved, Call.first.getGUID());
+ }
+ for (auto &GUID: FS->type_tests()) {
+ addPreservedGUID(Index, Preserved, GUID);
+ }
+ }
+ if (isa<AliasSummary>(GVSummary)) {
+ auto *AS = cast<AliasSummary>(GVSummary);
+ auto GUID = AS->getAliasee().getOriginalName();
+ addPreservedGUID(Index, Preserved, GUID);
+ }
+ }
+#else
auto SummaryList = Index.findGlobalValueSummaryList(GUID);
if (SummaryList == Index.end())
return;
addPreservedGUID(Index, Preserved, GUID);
}
}
+#endif
}
// The main entry point for creating the global ThinLTO analysis. The structure
Ret->ModuleMap[module->identifier] = mem_buffer;
+#if LLVM_VERSION_GE(5, 0)
+ if (Error Err = readModuleSummaryIndex(mem_buffer, Ret->Index, i)) {
+ LLVMRustSetLastError(toString(std::move(Err)).c_str());
+ return nullptr;
+ }
+#else
Expected<std::unique_ptr<object::ModuleSummaryIndexObjectFile>> ObjOrErr =
object::ModuleSummaryIndexObjectFile::create(mem_buffer);
if (!ObjOrErr) {
}
auto Index = (*ObjOrErr)->takeIndex();
Ret->Index.mergeFrom(std::move(Index), i);
+#endif
}
// Collect for each module the list of function it defines (GUID -> Summary)
// combined index
//
// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
+#if LLVM_VERSION_GE(5, 0)
+ computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
+ ComputeCrossModuleImport(
+ Ret->Index,
+ Ret->ModuleToDefinedGVSummaries,
+ Ret->ImportLists,
+ Ret->ExportLists
+ );
+#else
auto DeadSymbols = computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
ComputeCrossModuleImport(
Ret->Index,
Ret->ExportLists,
&DeadSymbols
);
+#endif
// Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
// impacts the caching.
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
for (auto &I : Ret->Index) {
+#if LLVM_VERSION_GE(5, 0)
+ if (I.second.SummaryList.size() > 1)
+ PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second.SummaryList);
+#else
if (I.second.size() > 1)
PrevailingCopy[I.first] = getFirstDefinitionForLinker(I.second);
+#endif
}
auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
const auto &Prevailing = PrevailingCopy.find(GUID);
mod inline {
//~ TRANS_ITEM fn local_inlining_but_not_all::inline[0]::inlined_function[0] @@ local_inlining_but_not_all-inline[External]
- #[inline(always)]
+ #[inline]
pub fn inlined_function()
{
// ignore-arm
// ignore-aarch64
-// min-llvm-version 3.8
// compile-flags: -C no-prepopulate-passes
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// The minimum LLVM version is set to 3.8, but really this test
-// depends on a patch that is was committed to upstream LLVM before
-// 4.0; and also backported to the Rust LLVM fork.
+// This test depends on a patch that was committed to upstream LLVM
+// before 4.0, formerly backported to the Rust LLVM fork.
// ignore-tidy-linelength
// ignore-windows
// ignore-macos
-// min-llvm-version 3.8
+// min-llvm-version 4.0
// compile-flags: -g -C no-prepopulate-passes
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// The minimum LLVM version is set to 3.8, but really this test
-// depends on a patch that is was committed to upstream LLVM before
-// 4.0; and also backported to the Rust LLVM fork.
+// This test depends on a patch that was committed to upstream LLVM
+// before 4.0, formerly backported to the Rust LLVM fork.
// ignore-tidy-linelength
// ignore-windows
// ignore-macos
-// min-llvm-version 3.8
+// min-llvm-version 4.0
// compile-flags: -g -C no-prepopulate-passes
mod inner { #![no_mangle="3500"] }
#[no_mangle = "3500"] fn f() { }
- //~^ WARN function f is marked #[no_mangle], but not exported
+ //~^ WARN function is marked #[no_mangle], but not exported
#[no_mangle = "3500"] struct S;
// compile-flags:-F private_no_mangle_fns -F no_mangle_const_items -F private_no_mangle_statics
-// FIXME(#19495) no_mangle'ing main ICE's.
#[no_mangle]
-fn foo() { //~ ERROR function foo is marked #[no_mangle], but not exported
+fn foo() { //~ ERROR function is marked #[no_mangle], but not exported
}
#[allow(dead_code)]
#[allow(dead_code)]
#[no_mangle]
-static PRIVATE_BAR: u64 = 1; //~ ERROR static PRIVATE_BAR is marked #[no_mangle], but not exported
+static PRIVATE_BAR: u64 = 1; //~ ERROR static is marked #[no_mangle], but not exported
fn main() {
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no asm! support
#![feature(asm, rustc_attrs)]
#![allow(unused)]
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Test that the outlives computation runs for now...
+
+#![feature(rustc_attrs)]
+
+//todo add all the test cases
+// https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md#example-1-a-reference
+
+#[rustc_outlives]
+struct Direct<'a, T> { //~ ERROR 19:1: 21:2: [] [E0640]
+ field: &'a T
+}
+
+fn main() { }
// END RUST SOURCE
// START rustc.node12.EraseRegions.after.mir
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[8cd8]::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[8cd8]::{{impl}}[0]::foo[0] }, BrAnon(1)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[e36f]::{{impl}}[0]::foo[0] }, BrAnon(0)) Test, _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:5) => validate_1[e36f]::{{impl}}[0]::foo[0] }, BrAnon(1)) mut i32]);
// ...
// return;
// }
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(50)], _2: &ReErased mut i32) -> i32 {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[e36f]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(50)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:11) => validate_1[e36f]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
// StorageLive(_3);
// _3 = _2;
// StorageLive(_4);
// fn write_42::{{closure}}(_1: &ReErased [closure@NodeId(22)], _2: *mut i32) -> () {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[8cd8]::write_42[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(22)], _2: *mut i32]);
-// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[8cd8]::write_42[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(22)], _2: *mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[e36f]::write_42[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(22)], _2: *mut i32]);
+// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_4[e36f]::write_42[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(22)], _2: *mut i32]);
// StorageLive(_3);
// _3 = _2;
// (*_3) = const 23i32;
// fn test(_1: &ReErased mut i32) -> () {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[8cd8]::test[0] }, BrAnon(0)) mut i32]);
-// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[8cd8]::test[0] }, BrAnon(0)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[e36f]::test[0] }, BrAnon(0)) mut i32]);
+// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_4[e36f]::test[0] }, BrAnon(0)) mut i32]);
// ...
// _3 = const write_42(_4) -> bb1;
// }
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(60)], _2: &ReErased mut i32) -> bool {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
-// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[e36f]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[e36f]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// Validate(Release, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[e36f]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(60)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:10) => validate_4[e36f]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
// StorageLive(_3);
// ...
// _0 = const write_42(_4) -> bb1;
// fn test(_1: &ReErased mut i32) -> () {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_5[8cd8]::test[0] }, BrAnon(0)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(0:4) => validate_5[e36f]::test[0] }, BrAnon(0)) mut i32]);
// ...
// Validate(Release, [_3: bool, _4: *mut i32]);
// _3 = const write_42(_4) -> bb1;
// fn main::{{closure}}(_1: &ReErased [closure@NodeId(46)], _2: &ReErased mut i32) -> bool {
// ...
// bb0: {
-// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[8cd8]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
+// Validate(Acquire, [_1: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[e36f]::main[0]::{{closure}}[0] }, BrEnv) [closure@NodeId(46)], _2: &ReFree(DefId { krate: CrateNum(0), index: DefIndex(1:9) => validate_5[e36f]::main[0]::{{closure}}[0] }, BrAnon(1)) mut i32]);
// StorageLive(_3);
// _3 = _2;
// StorageLive(_4);
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(RUSTC) foo.rs --emit llvm-ir -C codegen-units=2
+ if grep -w call $(TMPDIR)/*.ll; then \
+ echo "found call instruction when one wasn't expected"; \
+ exit 1; \
+ fi
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![crate_type = "lib"]
+
+pub mod a {
+ #[inline(always)]
+ pub fn foo() {
+ }
+
+ pub fn bar() {
+ }
+}
+
+#[no_mangle]
+pub fn bar() {
+ a::foo();
+}
// except according to those terms.
// pretty-expanded FIXME #23616
-// ignore-emscripten
+// ignore-emscripten no asm
#![feature(asm)]
// except according to those terms.
// ignore-windows - this is a unix-specific test
-// ignore-emscripten
+// ignore-emscripten no processes
#![feature(process_exec, libc)]
// ignore-windows - this is a unix-specific test
// ignore-pretty issue #37199
-// ignore-emscripten
+// ignore-emscripten no processes
+
#![feature(process_exec)]
use std::env;
// except according to those terms.
// compile-flags:--test
-// ignore-emscripten
+// ignore-emscripten no processes
// NB: These tests kill child processes. Valgrind sees these children as leaking
// memory, which makes for some *confusing* logs. That's why these are here
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::env::args;
use std::process::Command;
// ignore-android
// ignore-windows
-// ignore-emscripten
+// ignore-emscripten no execve
// no-prefer-dynamic
#![feature(libc)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten env vars don't work?
#![feature(path)]
// pretty-expanded FIXME #23616
// ignore-msvc
-// ignore-emscripten
+// ignore-emscripten emcc asserts on an empty struct as an argument
#[repr(C)]
struct TwoU8s {
// ignore-windows
// ignore-android
-// ignore-emscripten
+// ignore-emscripten no processes
// ignore-haiku
#![feature(libc)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten missing rust_begin_unwind
+// ignore-emscripten no no_std executables
#![feature(lang_items, start, alloc)]
#![no_std]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no threads support
// compile-flags: --test
#![feature(generators, generator_trait)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten i128 doesn't work
#![feature(i128_type, test)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
// Make sure that if a process doesn't have its stdio/stderr descriptors set up
// that we don't die in a large ball of fire
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
+
#![feature(io, process_capture)]
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
#![feature(io, process_capture)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::env;
use std::process::Command;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::process::Command;
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
+
#![feature(std_misc, os)]
#[cfg(unix)]
// except according to those terms.
// pretty-expanded FIXME #23616
-// ignore-emscripten
+// ignore-emscripten no threads
use std::thread::Builder;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no threads
use std::thread;
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no threads
// compile-flags: -O
// Tests that the `vec!` macro does not overflow the stack when it is
// except according to those terms.
// aux-build:issue-29485.rs
-// ignore-emscripten
+// ignore-emscripten no threads
#[feature(recover)]
// write_volatile causes an LLVM assert with composite types
-// ignore-emscripten See #41299: probably a bad optimization
-
#![feature(volatile)]
use std::ptr::{read_volatile, write_volatile};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
// Previously libstd would set stdio descriptors of a child process
// by `dup`ing the requested descriptors to inherit directly into the
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::process::{Command, Stdio};
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// min-llvm-version 3.9
-
use std::ops::Deref;
fn main() {
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ if false { test(); }
+}
+
+fn test() {
+ let rx = Err::<Vec<usize>, u32>(1).into_future();
+
+ rx.map(|l: Vec<usize>| stream::iter(l.into_iter().map(|i| Ok(i))))
+ .flatten_stream()
+ .chunks(50)
+ .buffer_unordered(5);
+}
+
+use future::{Future, IntoFuture};
+mod future {
+ use std::result;
+
+ use {stream, Stream};
+
+ pub trait Future {
+ type Item;
+ type Error;
+
+ fn map<F, U>(self, _: F) -> Map<Self, F>
+ where F: FnOnce(Self::Item) -> U,
+ Self: Sized,
+ {
+ panic!()
+ }
+
+ fn flatten_stream(self) -> FlattenStream<Self>
+ where <Self as Future>::Item: stream::Stream<Error=Self::Error>,
+ Self: Sized
+ {
+ panic!()
+ }
+ }
+
+ pub trait IntoFuture {
+ type Future: Future<Item=Self::Item, Error=Self::Error>;
+ type Item;
+ type Error;
+ fn into_future(self) -> Self::Future;
+ }
+
+ impl<F: Future> IntoFuture for F {
+ type Future = F;
+ type Item = F::Item;
+ type Error = F::Error;
+
+ fn into_future(self) -> F {
+ panic!()
+ }
+ }
+
+ impl<T, E> IntoFuture for result::Result<T, E> {
+ type Future = FutureResult<T, E>;
+ type Item = T;
+ type Error = E;
+
+ fn into_future(self) -> FutureResult<T, E> {
+ panic!()
+ }
+ }
+
+ pub struct Map<A, F> {
+ _a: (A, F),
+ }
+
+ impl<U, A, F> Future for Map<A, F>
+ where A: Future,
+ F: FnOnce(A::Item) -> U,
+ {
+ type Item = U;
+ type Error = A::Error;
+ }
+
+ pub struct FlattenStream<F> {
+ _f: F,
+ }
+
+ impl<F> Stream for FlattenStream<F>
+ where F: Future,
+ <F as Future>::Item: Stream<Error=F::Error>,
+ {
+ type Item = <F::Item as Stream>::Item;
+ type Error = <F::Item as Stream>::Error;
+ }
+
+ pub struct FutureResult<T, E> {
+ _inner: (T, E),
+ }
+
+ impl<T, E> Future for FutureResult<T, E> {
+ type Item = T;
+ type Error = E;
+ }
+}
+
+mod stream {
+ use IntoFuture;
+
+ pub trait Stream {
+ type Item;
+ type Error;
+
+ fn buffer_unordered(self, amt: usize) -> BufferUnordered<Self>
+ where Self::Item: IntoFuture<Error = <Self as Stream>::Error>,
+ Self: Sized
+ {
+ new(self, amt)
+ }
+
+ fn chunks(self, _capacity: usize) -> Chunks<Self>
+ where Self: Sized
+ {
+ panic!()
+ }
+ }
+
+ pub struct IterStream<I> {
+ _iter: I,
+ }
+
+ pub fn iter<J, T, E>(_: J) -> IterStream<J::IntoIter>
+ where J: IntoIterator<Item=Result<T, E>>,
+ {
+ panic!()
+ }
+
+ impl<I, T, E> Stream for IterStream<I>
+ where I: Iterator<Item=Result<T, E>>,
+ {
+ type Item = T;
+ type Error = E;
+ }
+
+ pub struct Chunks<S> {
+ _stream: S
+ }
+
+ impl<S> Stream for Chunks<S>
+ where S: Stream
+ {
+ type Item = Result<Vec<<S as Stream>::Item>, u32>;
+ type Error = <S as Stream>::Error;
+ }
+
+ pub struct BufferUnordered<S> {
+ _stream: S,
+ }
+
+ enum Slot<T> {
+ Next(usize),
+ _Data { _a: T },
+ }
+
+ fn new<S>(_s: S, _amt: usize) -> BufferUnordered<S>
+ where S: Stream,
+ S::Item: IntoFuture<Error=<S as Stream>::Error>,
+ {
+ (0..0).map(|_| {
+ Slot::Next::<<S::Item as IntoFuture>::Future>(1)
+ }).collect::<Vec<_>>();
+ panic!()
+ }
+
+ impl<S> Stream for BufferUnordered<S>
+ where S: Stream,
+ S::Item: IntoFuture<Error=<S as Stream>::Error>,
+ {
+ type Item = <S::Item as IntoFuture>::Item;
+ type Error = <S as Stream>::Error;
+ }
+}
+use stream::Stream;
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(never_type)]
+
+// Regression test for inhabitedness check. The old
+// cache used to cause us to incorrectly decide
+// that `test_b` was invalid.
+
+struct Foo {
+ field1: !,
+ field2: Option<&'static Bar>,
+}
+
+struct Bar {
+ field1: &'static Foo
+}
+
+fn test_a() {
+ let x: Option<Foo> = None;
+ match x { None => () }
+}
+
+fn test_b() {
+ let x: Option<Bar> = None;
+ match x { None => () }
+}
+
+fn main() { }
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(catch_expr)]
+
+fn main() {
+ let mut a = 0;
+ let () = {
+ let _: Result<(), ()> = do catch {
+ let _ = Err(())?;
+ return
+ };
+ a += 1;
+ };
+ a += 2;
+ assert_eq!(a, 3);
+}
// ignore-windows
// ignore-macos
-// ignore-emscripten
+// ignore-emscripten doesn't support this linkage
// aux-build:linkage1.rs
#![feature(linkage)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
fn check_for_no_backtrace(test: std::process::Output) {
assert!(!test.status.success());
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
// ignore-android
#![feature(libc)]
// ignore-android: FIXME (#20004)
// ignore-musl
-// ignore-emscripten
+// ignore-emscripten no processes
#![feature(asm)]
#![feature(libc)]
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten Not sure what's happening here.
-
use std::mem;
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
-
use std::mem;
// compile-flags:-C panic=abort
// aux-build:exit-success-if-unwind.rs
// no-prefer-dynamic
-// ignore-emscripten Function not implemented
+// ignore-emscripten no processes
extern crate exit_success_if_unwind;
// compile-flags:-C panic=abort
// no-prefer-dynamic
-// ignore-emscripten Function not implemented.
+// ignore-emscripten no processes
use std::process::Command;
use std::env;
// compile-flags:-C lto -C panic=abort
// no-prefer-dynamic
-// ignore-emscripten Function not implemented.
+// ignore-emscripten no processes
use std::process::Command;
use std::env;
// compile-flags:-C lto -C panic=unwind
// no-prefer-dynamic
-// ignore-emscripten Function not implemented.
+// ignore-emscripten no processes
use std::process::Command;
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::process::Command;
use std::env;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::env;
use std::process::{self, Command, Stdio};
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::process::Command;
use std::env;
// non-ASCII characters. The child process ensures all the strings are
// intact.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::io::prelude::*;
use std::io;
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten Function not implemented.
+
+// ignore-emscripten no processes
use std::env;
use std::io;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten spawning processes is not supported
#![feature(start)]
// except according to those terms.
// ignore-windows
-// ignore-emscripten
+// ignore-emscripten no processes
use std::env;
use std::process::Command;
// Be sure that when a SIGPIPE would have been received that the entire process
// doesn't die in a ball of fire, but rather it's gracefully handled.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::env;
use std::io::prelude::*;
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten linking with emcc failed
+
+// ignore-emscripten FIXME(#45351) hits an LLVM assert
#![feature(repr_simd, platform_intrinsics, concat_idents, test)]
#![allow(non_camel_case_types)]
// ignore-arm
// ignore-aarch64
// ignore-wasm
-// ignore-emscripten
+// ignore-emscripten no processes
// ignore-musl FIXME #31506
// ignore-pretty
// no-system-llvm
// ignore-arm
// ignore-aarch64
// ignore-wasm
-// ignore-emscripten
+// ignore-emscripten no processes
// ignore-musl FIXME #31506
// no-system-llvm
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
use std::env;
use std::io::prelude::*;
// compile-flags: -Z thinlto -C codegen-units=8 -O
// min-llvm-version 4.0
-// ignore-emscripten
+// ignore-emscripten can't inspect instructions on emscripten
// We want to assert here that ThinLTO will inline across codegen units. There's
// not really a great way to do that in general so we sort of hack around it by
// aux-build:thin-lto-inlines-aux.rs
// min-llvm-version 4.0
// no-prefer-dynamic
-// ignore-emscripten
+// ignore-emscripten can't inspect instructions on emscripten
// We want to assert here that ThinLTO will inline across codegen units. There's
// not really a great way to do that in general so we sort of hack around it by
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
#![feature(process_try_wait)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten u128 not supported
#![feature(i128_type, test)]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten missing rust_begin_unwind
+// ignore-emscripten no no_std executables
#![feature(lang_items, start, libc, alloc)]
#![no_std]
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// ignore-emscripten
+// ignore-emscripten no processes
#![feature(libc)]
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: --no-defaults --passes collapse-docs --passes unindent-comments --passes strip-priv-imports
+// compile-flags: --document-private-items
// @has 'empty_mod_private/index.html' '//a[@href="foo/index.html"]' 'foo'
// @has 'empty_mod_private/sidebar-items.js' 'foo'
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// compile-flags:--no-defaults --passes collapse-docs --passes unindent-comments
+// compile-flags: --no-defaults --passes collapse-docs --passes unindent-comments
// @has issue_15347/fn.foo.html
#[doc(hidden)]
// except according to those terms.
// ignore-tidy-linelength
-// compile-flags: --no-defaults --passes collapse-docs --passes unindent-comments --passes strip-priv-imports
+// compile-flags: --document-private-items
#![crate_name = "foo"]
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+fn main() {
+ let unused = ();
+
+ #![allow(unused_variables)]
+}
--- /dev/null
+error: an inner attribute is not permitted in this context
+ --> $DIR/issue-45296.rs:14:7
+ |
+14 | #![allow(unused_variables)]
+ | ^
+ |
+ = note: inner attributes and doc comments, like `#![no_std]` or `//! My crate`, annotate the item enclosing them, and are usually found at the beginning of source files. Outer attributes and doc comments, like `#[test]` and
+ `/// My function`, annotate the item following them.
+
+error: aborting due to previous error
+
#![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896
#![feature(no_debug)]
+#[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
+#[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
+
+#[no_mangle] // should suggest removal (generics can't be no-mangle)
+pub fn defiant<T>(_t: T) {}
+
+#[no_mangle]
+fn rio_grande() {} // should suggest `pub`
+
+struct Equinox {
+ warp_factor: f32,
+}
+
#[no_debug] // should suggest removal of deprecated attribute
fn main() {
while true { // should suggest `loop`
let mut a = (1); // should suggest no `mut`, no parens
+ let d = Equinox { warp_factor: 9.975 };
+ match d {
+ Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
+ }
println!("{}", a);
}
}
warning: unnecessary parentheses around assigned value
- --> $DIR/suggestions.rs:17:21
+ --> $DIR/suggestions.rs:30:21
|
-17 | let mut a = (1); // should suggest no `mut`, no parens
+30 | let mut a = (1); // should suggest no `mut`, no parens
| ^^^ help: remove these parentheses
|
= note: #[warn(unused_parens)] on by default
warning: use of deprecated attribute `no_debug`: the `#[no_debug]` attribute was an experimental feature that has been deprecated due to lack of demand. See https://github.com/rust-lang/rust/issues/29721
- --> $DIR/suggestions.rs:14:1
+ --> $DIR/suggestions.rs:27:1
|
-14 | #[no_debug] // should suggest removal of deprecated attribute
+27 | #[no_debug] // should suggest removal of deprecated attribute
| ^^^^^^^^^^^ help: remove this attribute
|
= note: #[warn(deprecated)] on by default
warning: variable does not need to be mutable
- --> $DIR/suggestions.rs:17:13
+ --> $DIR/suggestions.rs:30:13
|
-17 | let mut a = (1); // should suggest no `mut`, no parens
+30 | let mut a = (1); // should suggest no `mut`, no parens
| ---^^
| |
| help: remove this `mut`
11 | #![warn(unused_mut)] // UI tests pass `-A unused`—see Issue #43896
| ^^^^^^^^^^
+warning: static is marked #[no_mangle], but not exported
+ --> $DIR/suggestions.rs:14:14
+ |
+14 | #[no_mangle] static SHENZHOU: usize = 1; // should suggest `pub`
+ | -^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: try making it public: `pub `
+ |
+ = note: #[warn(private_no_mangle_statics)] on by default
+
+error: const items should never be #[no_mangle]
+ --> $DIR/suggestions.rs:15:14
+ |
+15 | #[no_mangle] const DISCOVERY: usize = 1; // should suggest `pub static` rather than `const`
+ | -----^^^^^^^^^^^^^^^^^^^^^^
+ | |
+ | help: try a static value: `pub static`
+ |
+ = note: #[deny(no_mangle_const_items)] on by default
+
+warning: functions generic over types must be mangled
+ --> $DIR/suggestions.rs:18:1
+ |
+17 | #[no_mangle] // should suggest removal (generics can't be no-mangle)
+ | ------------ help: remove this attribute
+18 | pub fn defiant<T>(_t: T) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: #[warn(no_mangle_generic_items)] on by default
+
+warning: function is marked #[no_mangle], but not exported
+ --> $DIR/suggestions.rs:21:1
+ |
+21 | fn rio_grande() {} // should suggest `pub`
+ | -^^^^^^^^^^^^^^^^^
+ | |
+ | help: try making it public: `pub `
+ |
+ = note: #[warn(private_no_mangle_fns)] on by default
+
warning: denote infinite loops with `loop { ... }`
- --> $DIR/suggestions.rs:16:5
+ --> $DIR/suggestions.rs:29:5
|
-16 | while true { // should suggest `loop`
+29 | while true { // should suggest `loop`
| ^---------
| |
| _____help: use `loop`
| |
-17 | | let mut a = (1); // should suggest no `mut`, no parens
-18 | | println!("{}", a);
-19 | | }
+30 | | let mut a = (1); // should suggest no `mut`, no parens
+31 | | let d = Equinox { warp_factor: 9.975 };
+32 | | match d {
+... |
+35 | | println!("{}", a);
+36 | | }
| |_____^
|
= note: #[warn(while_true)] on by default
+warning: the `warp_factor:` in this pattern is redundant
+ --> $DIR/suggestions.rs:33:23
+ |
+33 | Equinox { warp_factor: warp_factor } => {} // should suggest shorthand
+ | ------------^^^^^^^^^^^^
+ | |
+ | help: remove this
+ |
+ = note: #[warn(non_shorthand_field_patterns)] on by default
+
+error: aborting due to previous error
+
// compile-flags: --error-format json
-// ignore-windows (see Issue #44968)
-
// The output for humans should just highlight the whole span without showing
// the suggested replacement, but we also want to test that suggested
// replacement only removes one set of parentheses, rather than naïvely
-{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1014,"byte_end":1027,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(unused_parens)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":1014,"byte_end":1027,"line_start":24,"line_end":24,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":" let _a = 1 / (2 + 3);"}],"rendered":null}
+{"message":"unnecessary parentheses around assigned value","code":null,"level":"warning","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":null,"expansion":null}],"children":[{"message":"#[warn(unused_parens)] on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove these parentheses","code":null,"level":"help","spans":[{"file_name":"$DIR/unused_parens_json_suggestion.rs","byte_start":976,"byte_end":989,"line_start":22,"line_end":22,"column_start":14,"column_end":27,"is_primary":true,"text":[{"text":" let _a = (1 / (2 + 3));","highlight_start":14,"highlight_end":27}],"label":null,"suggested_replacement":"1 / (2 + 3)","expansion":null}],"children":[],"rendered":" let _a = 1 / (2 + 3);"}],"rendered":null}
fn normalize_output(&self, output: &str, custom_rules: &[(String, String)]) -> String {
let parent_dir = self.testpaths.file.parent().unwrap();
- let parent_dir_str = parent_dir.display().to_string();
+ let cflags = self.props.compile_flags.join(" ");
+ let parent_dir_str = if cflags.contains("--error-format json") {
+ parent_dir.display().to_string().replace("\\", "\\\\")
+ } else {
+ parent_dir.display().to_string()
+ };
+
let mut normalized = output.replace(&parent_dir_str, "$DIR")
+ .replace("\\\\", "\\") // denormalize for paths on windows
.replace("\\", "/") // normalize for paths on windows
.replace("\r\n", "\n") // normalize for linebreaks on windows
.replace("\t", "\\t"); // makes tabs visible
miri = "Broken"
# ping @Manishearth @llogiq @mcarton @oli-obk
-clippy = "Compiling"
+clippy = "Broken"
# ping @nrc
rls = "Testing"
# ping @nrc
rustfmt = "Testing"
-