fast_finish: true
include:
# Linux builders, all docker images
- - env: IMAGE=android DEPLOY=1
+ - env: IMAGE=arm-android
- env: IMAGE=armhf-gnu
- env: IMAGE=cross DEPLOY=1
- env: IMAGE=linux-tested-targets DEPLOY=1
+ - env: IMAGE=dist-android DEPLOY=1
- env: IMAGE=dist-arm-linux DEPLOY=1
- env: IMAGE=dist-armv7-aarch64-linux DEPLOY=1
- env: IMAGE=dist-freebsd DEPLOY=1
os: osx
osx_image: xcode8.2
install: &osx_install_sccache >
- curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 |
- tar xJf - -C /usr/local/bin --strip-components=1
+ travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin &&
+ chmod +x /usr/local/bin/sccache
- env: >
RUST_CHECK_TARGET=check
RUST_CONFIGURE_ARGS=--build=i686-apple-darwin
os: osx
osx_image: xcode8.2
install: >
- curl -L https://api.pub.build.mozilla.org/tooltool/sha512/d0025b286468cc5ada83b23d3fafbc936b9f190eaa7d4a981715b18e8e3bf720a7bcee7bfe758cfdeb8268857f6098fd52dcdd8818232692a30ce91039936596 |
- tar xJf - -C /usr/local/bin --strip-components=1 && brew uninstall --ignore-dependencies openssl && brew install openssl --universal --without-test
+ travis_retry curl -o /usr/local/bin/sccache https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-apple-darwin &&
+ chmod +x /usr/local/bin/sccache &&
+ brew uninstall --ignore-dependencies openssl &&
+ brew install openssl --universal --without-test
- env: >
RUST_CHECK_TARGET=dist
RUST_CONFIGURE_ARGS="--target=aarch64-apple-ios,armv7-apple-ios,armv7s-apple-ios,i386-apple-ios,x86_64-apple-ios --enable-extended"
+++ /dev/null
-# Compiler Test Documentation
-
-In the Rust project, we use a special set of commands embedded in
-comments to test the Rust compiler. There are two groups of commands:
-
-1. Header commands
-2. Error info commands
-
-Both types of commands are inside comments, but header commands should
-be in a comment before any code.
-
-## Summary of Error Info Commands
-
-Error commands specify something about certain lines of the
-program. They tell the test what kind of error and what message you
-are expecting.
-
-* `~`: Associates the following error level and message with the
- current line
-* `~|`: Associates the following error level and message with the same
- line as the previous comment
-* `~^`: Associates the following error level and message with the
- previous line. Each caret (`^`) that you add adds a line to this, so
- `~^^^^^^^` is seven lines up.
-
-The error levels that you can have are:
-
-1. `ERROR`
-2. `WARNING`
-3. `NOTE`
-4. `HELP` and `SUGGESTION`*
-
-\* **Note**: `SUGGESTION` must follow immediately after `HELP`.
-
-## Summary of Header Commands
-
-Header commands specify something about the entire test file as a
-whole, instead of just a few lines inside the test.
-
-* `ignore-X` where `X` is an architecture, OS or stage will ignore the test accordingly
-* `ignore-pretty` will not compile the pretty-printed test (this is done to test the pretty-printer, but might not always work)
-* `ignore-test` always ignores the test
-* `ignore-lldb` and `ignore-gdb` will skip the debuginfo tests
-* `min-{gdb,lldb}-version`
-* `should-fail` indicates that the test should fail; used for "meta testing",
- where we test the compiletest program itself to check that it will generate
- errors in appropriate scenarios. This header is ignored for pretty-printer tests.
-* `gate-test-X` where `X` is a feature marks the test as "gate test" for feature X.
- Such tests are supposed to ensure that the compiler errors when usage of a gated
- feature is attempted without the proper `#![feature(X)]` tag.
- Each unstable lang feature is required to have a gate test.
-
-## Revisions
-
-Certain classes of tests support "revisions" (as of the time of this
-writing, this includes run-pass, compile-fail, run-fail, and
-incremental, though incremental tests are somewhat
-different). Revisions allow a single test file to be used for multiple
-tests. This is done by adding a special header at the top of the file:
-
-```
-// revisions: foo bar baz
-```
-
-This will result in the test being compiled (and tested) three times,
-once with `--cfg foo`, once with `--cfg bar`, and once with `--cfg
-baz`. You can therefore use `#[cfg(foo)]` etc within the test to tweak
-each of these results.
-
-You can also customize headers and expected error messages to a particular
-revision. To do this, add `[foo]` (or `bar`, `baz`, etc) after the `//`
-comment, like so:
-
-```
-// A flag to pass in only for cfg `foo`:
-//[foo]compile-flags: -Z verbose
-
-#[cfg(foo)]
-fn test_foo() {
- let x: usize = 32_u32; //[foo]~ ERROR mismatched types
-}
-```
-
-Note that not all headers have meaning when customized to a revision.
-For example, the `ignore-test` header (and all "ignore" headers)
-currently only apply to the test as a whole, not to particular
-revisions. The only headers that are intended to really work when
-customized to a revision are error patterns and compiler flags.
Before you can start building the compiler you need to configure the build for
your system. In most cases, that will just mean using the defaults provided
-for Rust. Configuring involves invoking the `configure` script in the project
-root.
+for Rust.
-```
-./configure
-```
+To change configuration, you must copy the file `src/bootstrap/config.toml.example`
+to `config.toml` in the directory from which you will be running the build, and
+change the settings provided.
+
+There are large number of options provided in this config file that will alter the
+configuration used in the build process. Some options to note:
-There are large number of options accepted by this script to alter the
-configuration used later in the build process. Some options to note:
+#### `[llvm]`:
+- `ccache = true` - Use ccache when building llvm
-- `--enable-debug` - Build a debug version of the compiler (disables optimizations,
- which speeds up compilation of stage1 rustc)
-- `--enable-optimize` - Enable optimizations (can be used with `--enable-debug`
- to make a debug build with optimizations)
-- `--disable-valgrind-rpass` - Don't run tests with valgrind
-- `--enable-clang` - Prefer clang to gcc for building dependencies (e.g., LLVM)
-- `--enable-ccache` - Invoke clang/gcc with ccache to re-use object files between builds
-- `--enable-compiler-docs` - Build compiler documentation
+#### `[build]`:
+- `compiler-docs = true` - Build compiler documentation
-To see a full list of options, run `./configure --help`.
+#### `[rust]`:
+- `debuginfo = true` - Build a compiler with debuginfo
+- `optimize = false` - Disable optimizations to speed up compilation of stage1 rust
+
+For more options, the `config.toml` file contains commented out defaults, with
+descriptions of what each option will do.
+
+Note: Previously the `./configure` script was used to configure this
+project. It can still be used, but it's recommended to use a `config.toml`
+file. If you still have a `config.mk` file in your directory - from
+`./configure` - you may need to delete it for `config.toml` to work.
### Building
-Although the `./configure` script will generate a `Makefile`, this is actually
-just a thin veneer over the actual build system driver, `x.py`. This file, at
-the root of the repository, is used to build, test, and document various parts
-of the compiler. You can execute it as:
+The build system uses the `x.py` script to control the build process. This script
+is used to build, test, and document various parts of the compiler. You can
+execute it as:
```sh
python x.py build
python x.py build --help --verbose
```
+Note: Previously `./configure` and `make` were used to build this project.
+They are still available, but `x.py` is the recommended build system.
+
### Useful commands
Some common invocations of `x.py` are:
Please make pull requests against the `master` branch.
-Compiling all of `make check` can take a while. When testing your pull request,
-consider using one of the more specialized `make` targets to cut down on the
+Compiling all of `./x.py test` can take a while. When testing your pull request,
+consider using one of the more specialized `./x.py` targets to cut down on the
amount of time you have to wait. You need to have built the compiler at least
once before running these will work, but that’s only one full build rather than
one each time.
[adocs]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-docs
-In many cases, you don't need a full `make doc`. You can use `rustdoc` directly
+In many cases, you don't need a full `./x.py doc`. You can use `rustdoc` directly
to check small fixes. For example, `rustdoc src/doc/reference.md` will render
reference to `doc/reference.html`. The CSS might be messed up, but you can
verify that the HTML is right.
3. Build and install:
```sh
- $ ./configure
- $ make && sudo make install
+ $ ./x.py build && sudo ./x.py dist --install
```
- > ***Note:*** Install locations can be adjusted by passing a `--prefix`
- > argument to `configure`. Various other options are also supported – pass
- > `--help` for more information on them.
+ > ***Note:*** Install locations can be adjusted by copying the config file
+ > from `./src/bootstrap/config.toml.example` to `./config.toml`, and
+ > adjusting the `prefix` option under `[install]`. Various other options are
+ > also supported, and are documented in the config file.
- When complete, `sudo make install` will place several programs into
+ When complete, `sudo ./x.py dist --install` will place several programs into
`/usr/local/bin`: `rustc`, the Rust compiler, and `rustdoc`, the
API-documentation tool. This install does not include [Cargo],
Rust's package manager, which you may also want to build.
for interop with GNU software built using the MinGW/MSYS2 toolchain use the GNU
build.
-
#### MinGW
[MSYS2][msys2] can be used to easily build Rust on Windows:
mingw-w64-x86_64-gcc
```
-4. Navigate to Rust's source code (or clone it), then configure and build it:
+4. Navigate to Rust's source code (or clone it), then build it:
```sh
- $ ./configure
- $ make && make install
+ $ ./x.py build && ./x.py dist --install
```
#### MSVC
> python x.py build
```
-If you're running inside of an msys shell, however, you can run:
-
-```sh
-$ ./configure --build=x86_64-pc-windows-msvc
-$ make && make install
-```
-
Currently building Rust only works with some known versions of Visual Studio. If
you have a more recent version installed the build system doesn't understand
then you may need to force rustbuild to use an older version. This can be done
python x.py build
```
+#### Specifying an ABI
+
+Each specific ABI can also be used from either environment (for example, using
+the GNU ABI in powershell) by using an explicit build triple. The available
+Windows build triples are:
+- GNU ABI (using GCC)
+ - `i686-pc-windows-gnu`
+ - `x86_64-pc-windows-gnu`
+- The MSVC ABI
+ - `i686-pc-windows-msvc`
+ - `x86_64-pc-windows-msvc`
+
+The build triple can be specified by either specifying `--build=ABI` when
+invoking `x.py` commands, or by copying the `config.toml` file (as described
+in Building From Source), and modifying the `build` option under the `[build]`
+section.
+
+### Configure and Make
+
+While it's not the recommended build system, this project also provides a
+configure script and makefile (the latter of which just invokes `x.py`).
+
+```sh
+$ ./configure
+$ make && sudo make install
+```
+
+When using the configure script, the generated config.mk` file may override the
+`config.toml` file. To go back to the `config.toml` file, delete the generated
+`config.mk` file.
+
## Building Documentation
If you’d like to build the documentation, it’s almost the same:
```sh
-$ ./configure
-$ make docs
+$ ./x.py doc
```
The generated documentation will appear in a top-level `doc` directory,
# /usr/bin/python2.7.exe is not. To ensure we use the right interpreter we
# move `C:\Python27` ahead in PATH and then also make sure the `python2.7.exe`
# file exists in there (which it doesn't by default).
- - if defined MINGW_URL appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE%
+ - if defined MINGW_URL appveyor-retry appveyor DownloadFile %MINGW_URL%/%MINGW_ARCHIVE%
- if defined MINGW_URL 7z x -y %MINGW_ARCHIVE% > nul
- if defined MINGW_URL set PATH=%CD%\%MINGW_DIR%\bin;C:\msys64\usr\bin;%PATH%
- set PATH=C:\Python27;%PATH%
# Download and install sccache
- - appveyor DownloadFile https://api.pub.build.mozilla.org/tooltool/sha512/%SCCACHE_DIGEST%
- - mv %SCCACHE_DIGEST% sccache.tar.bz2
- - 7z x -y sccache.tar.bz2 > nul
- - 7z x -y sccache.tar > nul
- - set PATH=%PATH%;%CD%\sccache2
+ - appveyor-retry appveyor DownloadFile https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-pc-windows-msvc
+ - mv 2017-02-25-sccache-x86_64-pc-windows-msvc sccache
+ - set PATH=%PATH%;%CD%
# Install InnoSetup to get `iscc` used to produce installers
- - choco install -y InnoSetup
+ - appveyor-retry choco install -y InnoSetup
- set PATH="C:\Program Files (x86)\Inno Setup 5";%PATH%
# Help debug some handle issues on AppVeyor
- handle.exe -accepteula -help
test_script:
- - git submodule update --init
+ - appveyor-retry sh -c 'git submodule deinit -f . && git submodule update --init'
- set SRC=.
- set NO_CCACHE=1
- sh src/ci/run.sh
cache:
- - "build/i686-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
- - "build/x86_64-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
- "build/i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
- "build/x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
- - "i686-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
- - "x86_64-pc-windows-gnu/llvm -> src/rustllvm/llvm-auto-clean-trigger"
- "i686-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
- "x86_64-pc-windows-msvc/llvm -> src/rustllvm/llvm-auto-clean-trigger"
};
let stage = env::var("RUSTC_STAGE").expect("RUSTC_STAGE was not set");
let sysroot = env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set");
+ let mut on_fail = env::var_os("RUSTC_ON_FAIL").map(|of| Command::new(of));
let rustc = env::var_os(rustc).unwrap_or_else(|| panic!("{:?} was not set", rustc));
let libdir = env::var_os(libdir).unwrap_or_else(|| panic!("{:?} was not set", libdir));
}
// Actually run the compiler!
- std::process::exit(match exec_cmd(&mut cmd) {
- Ok(s) => s.code().unwrap_or(0xfe),
- Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
+ std::process::exit(if let Some(ref mut on_fail) = on_fail {
+ match cmd.status() {
+ Ok(s) if s.success() => 0,
+ _ => {
+ println!("\nDid not run successfully:\n{:?}\n-------------", cmd);
+ exec_cmd(on_fail).expect("could not run the backup command");
+ 1
+ }
+ }
+ } else {
+ std::process::exit(match exec_cmd(&mut cmd) {
+ Ok(s) => s.code().unwrap_or(0xfe),
+ Err(e) => panic!("\n\nfailed to run {:?}: {}\n\n", cmd, e),
+ })
})
}
def download(path, url, probably_big, verbose):
+ for x in range(0, 4):
+ try:
+ _download(path, url, probably_big, verbose, True)
+ return
+ except RuntimeError:
+ print("\nspurious failure, trying again")
+ _download(path, url, probably_big, verbose, False)
+
+
+def _download(path, url, probably_big, verbose, exception):
if probably_big or verbose:
print("downloading {}".format(url))
# see http://serverfault.com/questions/301128/how-to-download
run(["PowerShell.exe", "/nologo", "-Command",
"(New-Object System.Net.WebClient)"
".DownloadFile('{}', '{}')".format(url, path)],
- verbose=verbose)
+ verbose=verbose,
+ exception=exception)
else:
if probably_big or verbose:
option = "-#"
else:
option = "-s"
- run(["curl", option, "--retry", "3", "-Sf", "-o", path, url], verbose=verbose)
+ run(["curl", option, "--retry", "3", "-Sf", "-o", path, url],
+ verbose=verbose,
+ exception=exception)
def verify(path, sha_path, verbose):
shutil.move(tp, fp)
shutil.rmtree(os.path.join(dst, fname))
-def run(args, verbose=False):
+def run(args, verbose=False, exception=False):
if verbose:
print("running: " + ' '.join(args))
sys.stdout.flush()
code = ret.wait()
if code != 0:
err = "failed to run: " + ' '.join(args)
- if verbose:
+ if verbose or exception:
raise RuntimeError(err)
sys.exit(err)
env = os.environ.copy()
env["CARGO_TARGET_DIR"] = build_dir
env["RUSTC"] = self.rustc()
- env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
- env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib")
+ env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
+ (os.pathsep + env["LD_LIBRARY_PATH"]) \
+ if "LD_LIBRARY_PATH" in env else ""
+ env["DYLD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \
+ (os.pathsep + env["DYLD_LIBRARY_PATH"]) \
+ if "DYLD_LIBRARY_PATH" in env else ""
env["PATH"] = os.path.join(self.bin_root(), "bin") + \
os.pathsep + env["PATH"]
if not os.path.isfile(self.cargo()):
ostype += 'abi64'
elif cputype in {'powerpc', 'ppc', 'ppc64'}:
cputype = 'powerpc'
+ elif cputype == 'sparcv9':
+ pass
elif cputype in {'amd64', 'x86_64', 'x86-64', 'x64'}:
cputype = 'x86_64'
else:
/// Deserialized version of all flags for this compile.
pub struct Flags {
pub verbose: usize, // verbosity level: 0 == not verbose, 1 == verbose, 2 == very verbose
+ pub on_fail: Option<String>,
pub stage: Option<u32>,
pub keep_stage: Option<u32>,
pub build: String,
opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
opts.optmulti("", "host", "host targets to build", "HOST");
opts.optmulti("", "target", "target targets to build", "TARGET");
+ opts.optopt("", "on-fail", "command to run on failure", "CMD");
opts.optopt("", "stage", "stage to build", "N");
opts.optopt("", "keep-stage", "stage to keep without recompiling", "N");
opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
Flags {
verbose: m.opt_count("v"),
stage: stage,
+ on_fail: m.opt_str("on-fail"),
keep_stage: m.opt_str("keep-stage").map(|j| j.parse().unwrap()),
build: m.opt_str("build").unwrap_or_else(|| {
env::var("BUILD").unwrap()
cargo.env("RUSTC_INCREMENTAL", incr_dir);
}
+ if let Some(ref on_fail) = self.flags.on_fail {
+ cargo.env("RUSTC_ON_FAIL", on_fail);
+ }
+
let verbose = cmp::max(self.config.verbose, self.flags.verbose);
cargo.env("RUSTC_VERBOSE", format!("{}", verbose));
if target.contains("apple-darwin") {
base.push("-stdlib=libc++".into());
}
- // This is a hack, because newer binutils broke things on some vms/distros
- // (i.e., linking against unknown relocs disabled by the following flag)
- // See: https://github.com/rust-lang/rust/issues/34978
- match target {
- "i586-unknown-linux-gnu" |
- "i686-unknown-linux-musl" |
- "x86_64-unknown-linux-musl" => {
- base.push("-Wa,-mrelax-relocations=no".into());
- },
- _ => {},
- }
return base
}
$(Q)$(BOOTSTRAP) dist --install $(BOOTSTRAP_ARGS)
tidy:
$(Q)$(BOOTSTRAP) test src/tools/tidy $(BOOTSTRAP_ARGS)
+prepare:
+ $(Q)$(BOOTSTRAP) build nonexistent/path/to/trigger/cargo/metadata
check-stage2-T-arm-linux-androideabi-H-x86_64-unknown-linux-gnu:
$(Q)$(BOOTSTRAP) test --target arm-linux-androideabi
");
}
}
-
- if target.contains("arm-linux-android") {
- need_cmd("adb".as_ref());
- }
}
for host in build.flags.host.iter() {
+++ /dev/null
-FROM ubuntu:16.04
-
-RUN dpkg --add-architecture i386 && \
- apt-get update && \
- apt-get install -y --no-install-recommends \
- g++ \
- make \
- file \
- curl \
- ca-certificates \
- python2.7 \
- git \
- cmake \
- unzip \
- expect \
- openjdk-9-jre \
- sudo \
- libstdc++6:i386 \
- xz-utils \
- libssl-dev \
- pkg-config
-
-WORKDIR /android/
-ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
-
-COPY install-ndk.sh install-sdk.sh accept-licenses.sh /android/
-RUN sh /android/install-ndk.sh
-RUN sh /android/install-sdk.sh
-
-RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
- dpkg -i dumb-init_*.deb && \
- rm dumb-init_*.deb
-
-COPY start-emulator.sh /android/
-
-ENTRYPOINT ["/usr/bin/dumb-init", "--", "/android/start-emulator.sh"]
-
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
-
-ENV TARGETS=arm-linux-androideabi
-ENV TARGETS=$TARGETS,i686-linux-android
-ENV TARGETS=$TARGETS,aarch64-linux-android
-ENV TARGETS=$TARGETS,armv7-linux-androideabi
-
-ENV RUST_CONFIGURE_ARGS \
- --target=$TARGETS \
- --arm-linux-androideabi-ndk=/android/ndk-arm-9 \
- --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \
- --i686-linux-android-ndk=/android/ndk-x86-9 \
- --aarch64-linux-android-ndk=/android/ndk-aarch64
-
-# Just a smoke test in dist to see if this works for now, we should expand this
-# to all the targets above eventually.
-ENV SCRIPT \
- python2.7 ../x.py test --target arm-linux-androideabi && \
- python2.7 ../x.py dist --target $TARGETS
+++ /dev/null
-#!/usr/bin/expect -f
-# ignore-license
-
-set timeout 1800
-set cmd [lindex $argv 0]
-set licenses [lindex $argv 1]
-
-spawn {*}$cmd
-expect {
- "Do you accept the license '*'*" {
- exp_send "y\r"
- exp_continue
- }
- eof
-}
+++ /dev/null
-#!/bin/sh
-# 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.
-
-set -ex
-
-cpgdb() {
- cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb /android/$1/bin/$2-gdb
- cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb-orig /android/$1/bin/gdb-orig
- cp -r android-ndk-r11c/prebuilt/linux-x86_64/share /android/$1/share
-}
-
-# Prep the Android NDK
-#
-# See https://github.com/servo/servo/wiki/Building-for-Android
-curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip
-unzip -q android-ndk-r11c-linux-x86_64.zip
-bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
- --platform=android-9 \
- --toolchain=arm-linux-androideabi-4.9 \
- --install-dir=/android/ndk-arm-9 \
- --ndk-dir=/android/android-ndk-r11c \
- --arch=arm
-cpgdb ndk-arm-9 arm-linux-androideabi
-bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
- --platform=android-21 \
- --toolchain=aarch64-linux-android-4.9 \
- --install-dir=/android/ndk-aarch64 \
- --ndk-dir=/android/android-ndk-r11c \
- --arch=arm64
-bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
- --platform=android-9 \
- --toolchain=x86-4.9 \
- --install-dir=/android/ndk-x86-9 \
- --ndk-dir=/android/android-ndk-r11c \
- --arch=x86
-
-rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c
+++ /dev/null
-#!/bin/sh
-# 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.
-
-set -ex
-
-# Prep the SDK and emulator
-#
-# Note that the update process requires that we accept a bunch of licenses, and
-# we can't just pipe `yes` into it for some reason, so we take the same strategy
-# located in https://github.com/appunite/docker by just wrapping it in a script
-# which apparently magically accepts the licenses.
-
-mkdir sdk
-curl https://dl.google.com/android/android-sdk_r24.4-linux.tgz | \
- tar xzf - -C sdk --strip-components=1
-
-filter="platform-tools,android-18"
-filter="$filter,sys-img-armeabi-v7a-android-18"
-
-./accept-licenses.sh "android - update sdk -a --no-ui --filter $filter"
-
-echo "no" | android create avd \
- --name arm-18 \
- --target android-18 \
- --abi armeabi-v7a
+++ /dev/null
-#!/bin/sh
-# 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.
-
-set -ex
-ANDROID_EMULATOR_FORCE_32BIT=true \
- nohup nohup emulator @arm-18 -no-window -partition-size 2047 \
- 0<&- &>/dev/null &
-exec "$@"
--- /dev/null
+FROM ubuntu:16.04
+
+RUN dpkg --add-architecture i386 && \
+ apt-get update && \
+ apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ unzip \
+ expect \
+ openjdk-9-jre \
+ sudo \
+ libstdc++6:i386 \
+ xz-utils \
+ libssl-dev \
+ pkg-config
+
+WORKDIR /android/
+ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
+
+COPY install-ndk.sh install-sdk.sh accept-licenses.sh /android/
+RUN sh /android/install-ndk.sh
+RUN sh /android/install-sdk.sh
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+ dpkg -i dumb-init_*.deb && \
+ rm dumb-init_*.deb
+
+COPY start-emulator.sh /android/
+
+ENTRYPOINT ["/usr/bin/dumb-init", "--", "/android/start-emulator.sh"]
+
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-24-sccache-x86_64-unknown-linux-gnu && \
+ chmod +x /usr/local/bin/sccache
+
+ENV RUST_CONFIGURE_ARGS \
+ --target=arm-linux-androideabi \
+ --arm-linux-androideabi-ndk=/android/ndk-arm-9
+
+ENV SCRIPT python2.7 ../x.py test --target arm-linux-androideabi
--- /dev/null
+#!/usr/bin/expect -f
+# ignore-license
+
+set timeout 1800
+set cmd [lindex $argv 0]
+set licenses [lindex $argv 1]
+
+spawn {*}$cmd
+expect {
+ "Do you accept the license '*'*" {
+ exp_send "y\r"
+ exp_continue
+ }
+ eof
+}
--- /dev/null
+#!/bin/sh
+# 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.
+
+set -ex
+
+cpgdb() {
+ cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb /android/$1/bin/$2-gdb
+ cp android-ndk-r11c/prebuilt/linux-x86_64/bin/gdb-orig /android/$1/bin/gdb-orig
+ cp -r android-ndk-r11c/prebuilt/linux-x86_64/share /android/$1/share
+}
+
+# Prep the Android NDK
+#
+# See https://github.com/servo/servo/wiki/Building-for-Android
+curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip
+unzip -q android-ndk-r11c-linux-x86_64.zip
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+ --platform=android-9 \
+ --toolchain=arm-linux-androideabi-4.9 \
+ --install-dir=/android/ndk-arm-9 \
+ --ndk-dir=/android/android-ndk-r11c \
+ --arch=arm
+cpgdb ndk-arm-9 arm-linux-androideabi
+
+rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c
--- /dev/null
+#!/bin/sh
+# 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.
+
+set -ex
+
+# Prep the SDK and emulator
+#
+# Note that the update process requires that we accept a bunch of licenses, and
+# we can't just pipe `yes` into it for some reason, so we take the same strategy
+# located in https://github.com/appunite/docker by just wrapping it in a script
+# which apparently magically accepts the licenses.
+
+mkdir sdk
+curl https://dl.google.com/android/android-sdk_r24.4-linux.tgz | \
+ tar xzf - -C sdk --strip-components=1
+
+filter="platform-tools,android-18"
+filter="$filter,sys-img-armeabi-v7a-android-18"
+
+./accept-licenses.sh "android - update sdk -a --no-ui --filter $filter"
+
+echo "no" | android create avd \
+ --name arm-18 \
+ --target android-18 \
+ --abi armeabi-v7a
--- /dev/null
+#!/bin/sh
+# 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.
+
+set -ex
+ANDROID_EMULATOR_FORCE_32BIT=true \
+ nohup nohup emulator @arm-18 -no-window -partition-size 2047 \
+ 0<&- &>/dev/null &
+exec "$@"
# TODO: What is this?!
RUN curl -O http://ftp.nl.debian.org/debian/dists/jessie/main/installer-armhf/current/images/device-tree/vexpress-v2p-ca15-tc1.dtb
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
libssl-dev \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
--- /dev/null
+FROM ubuntu:16.04
+
+RUN dpkg --add-architecture i386 && \
+ apt-get update && \
+ apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ unzip \
+ expect \
+ openjdk-9-jre \
+ sudo \
+ libstdc++6:i386 \
+ xz-utils \
+ libssl-dev \
+ pkg-config
+
+WORKDIR /android/
+ENV PATH=$PATH:/android/ndk-arm-9/bin:/android/sdk/tools:/android/sdk/platform-tools
+
+COPY install-ndk.sh /android/
+RUN sh /android/install-ndk.sh
+
+RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
+ dpkg -i dumb-init_*.deb && \
+ rm dumb-init_*.deb
+ENTRYPOINT ["/usr/bin/dumb-init", "--"]
+
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
+
+ENV TARGETS=arm-linux-androideabi
+ENV TARGETS=$TARGETS,i686-linux-android
+ENV TARGETS=$TARGETS,aarch64-linux-android
+ENV TARGETS=$TARGETS,armv7-linux-androideabi
+
+ENV RUST_CONFIGURE_ARGS \
+ --target=$TARGETS \
+ --arm-linux-androideabi-ndk=/android/ndk-arm-9 \
+ --armv7-linux-androideabi-ndk=/android/ndk-arm-9 \
+ --i686-linux-android-ndk=/android/ndk-x86-9 \
+ --aarch64-linux-android-ndk=/android/ndk-aarch64
+
+ENV SCRIPT python2.7 ../x.py dist --target $TARGETS
--- /dev/null
+#!/bin/sh
+# 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.
+
+set -ex
+
+# Prep the Android NDK
+#
+# See https://github.com/servo/servo/wiki/Building-for-Android
+curl -O https://dl.google.com/android/repository/android-ndk-r11c-linux-x86_64.zip
+unzip -q android-ndk-r11c-linux-x86_64.zip
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+ --platform=android-9 \
+ --toolchain=arm-linux-androideabi-4.9 \
+ --install-dir=/android/ndk-arm-9 \
+ --ndk-dir=/android/android-ndk-r11c \
+ --arch=arm
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+ --platform=android-21 \
+ --toolchain=aarch64-linux-android-4.9 \
+ --install-dir=/android/ndk-aarch64 \
+ --ndk-dir=/android/android-ndk-r11c \
+ --arch=arm64
+bash android-ndk-r11c/build/tools/make-standalone-toolchain.sh \
+ --platform=android-9 \
+ --toolchain=x86-4.9 \
+ --install-dir=/android/ndk-x86-9 \
+ --ndk-dir=/android/android-ndk-r11c \
+ --arch=x86
+
+rm -rf ./android-ndk-r11c-linux-x86_64.zip ./android-ndk-r11c
libssl-dev \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
libssl-dev \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
ENV \
AR_x86_64_unknown_freebsd=x86_64-unknown-freebsd10-ar \
libssl-dev \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
libssl-dev \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
libssl-dev \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
libssl-dev \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
libssl-dev \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
chmod +x /rustroot/dumb-init
ENTRYPOINT ["/rustroot/dumb-init", "--"]
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- xz --decompress | \
- tar xf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
ENV HOSTS=i686-unknown-linux-gnu
ENV HOSTS=$HOSTS,x86_64-unknown-linux-gnu
xz-utils \
lib32stdc++6
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
gdb \
xz-utils
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
gdb \
xz-utils
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
rm dumb-init_*.deb
ENTRYPOINT ["/usr/bin/dumb-init", "--"]
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
ENV RUST_CONFIGURE_ARGS \
--target=x86_64-unknown-linux-musl,i686-unknown-linux-musl,i586-unknown-linux-gnu \
--musl-root-x86_64=/musl-x86_64 \
--musl-root-i686=/musl-i686
+# Newer binutils broke things on some vms/distros (i.e., linking against
+# unknown relocs disabled by the following flag), so we need to go out of our
+# way to produce "super compatible" binaries.
+#
+# See: https://github.com/rust-lang/rust/issues/34978
+ENV CFLAGS_i686_unknown_linux_gnu=-Wa,-mrelax-relocations=no \
+ CFLAGS_x86_64_unknown_linux_gnu=-Wa,-mrelax-relocations=no
+
ENV SCRIPT \
python2.7 ../x.py test \
--target x86_64-unknown-linux-musl \
set -ex
-export CFLAGS="-fPIC"
+# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well
+export CFLAGS="-fPIC -Wa,-mrelax-relocations=no"
+export CXXFLAGS="-Wa,-mrelax-relocations=no"
+
MUSL=musl-1.1.14
curl https://www.musl-libc.org/releases/$MUSL.tar.gz | tar xzf -
cd $MUSL
-#!/bin/sh
+#!/bin/bash
# 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.
src_dir="`dirname $ci_dir`"
root_dir="`dirname $src_dir`"
-docker \
+source "$ci_dir/shared.sh"
+
+retry docker \
build \
--rm \
-t rust-ci \
xz-utils \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
gdb \
xz-utils
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
libssl-dev \
pkg-config
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
gdb \
xz-utils
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
gdb \
xz-utils
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
zlib1g-dev \
xz-utils
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
gdb \
xz-utils
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
gdb \
xz-utils
-ENV SCCACHE_DIGEST=7237e38e029342fa27b7ac25412cb9d52554008b12389727320bd533fd7f05b6a96d55485f305caf95e5c8f5f97c3313e10012ccad3e752aba2518f3522ba783
-RUN curl -L https://api.pub.build.mozilla.org/tooltool/sha512/$SCCACHE_DIGEST | \
- tar xJf - -C /usr/local/bin --strip-components=1
+RUN curl -o /usr/local/bin/sccache \
+ https://s3.amazonaws.com/rust-lang-ci/rust-ci-mirror/2017-02-25-sccache-x86_64-unknown-linux-musl && \
+ chmod +x /usr/local/bin/sccache
RUN curl -OL https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb && \
dpkg -i dumb-init_*.deb && \
-#!/bin/sh
+#!/bin/bash
# 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.
fi
fi
+ci_dir=`cd $(dirname $0) && pwd`
+source "$ci_dir/shared.sh"
+
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-sccache"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-quiet-tests"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-manage-submodules"
fi
fi
-set -ex
-
$SRC/configure $RUST_CONFIGURE_ARGS
+retry make prepare
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
ncpus=$(sysctl -n hw.ncpu)
ncpus=$(grep processor /proc/cpuinfo | wc -l)
fi
+set -x
+
if [ ! -z "$SCRIPT" ]; then
sh -x -c "$SCRIPT"
else
--- /dev/null
+#!/bin/bash
+# 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.
+
+# See http://unix.stackexchange.com/questions/82598
+function retry {
+ local n=1
+ local max=5
+ local delay=15
+ while true; do
+ echo "Attempting:" "$@"
+ "$@" && break || {
+ if [[ $n -lt $max ]]; then
+ ((n++))
+ echo "Command failed. Attempt $n/$max:"
+ else
+ echo "The command has failed after $n attempts."
+ exit 1
+ fi
+ }
+ done
+}
implemented for that type.
In the opposite way, if we were wrapping a library with [FFI][ffi] that isn't
-threadsafe, we wouldn't want to implement `Send`, and so the compiler will help
+thread-safe, we wouldn't want to implement `Send`, and so the compiler will help
us enforce that it can't leave the current thread.
[ffi]: ffi.html
* Static - `#[link(name = "my_build_dependency", kind = "static")]`
* Frameworks - `#[link(name = "CoreFoundation", kind = "framework")]`
-Note that frameworks are only available on OSX targets.
+Note that frameworks are only available on macOS targets.
The different `kind` values are meant to differentiate how the native library
participates in linkage. From a linkage perspective, the Rust compiler creates
is included in a final target (like a binary), the native library will be
linked in.
-On OSX, frameworks behave with the same semantics as a dynamic library.
+On macOS, frameworks behave with the same semantics as a dynamic library.
# Unsafe blocks
```text
$ RUST_BACKTRACE=1 ./diverges
thread 'main' panicked at 'This function never returns!', hello.rs:2
+Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
+stack backtrace:
+ hello::diverges
+ at ./hello.rs:2
+ hello::main
+ at ./hello.rs:6
+```
+
+If you want the complete backtrace and filenames:
+
+```text
+$ RUST_BACKTRACE=full ./diverges
+thread 'main' panicked at 'This function never returns!', hello.rs:2
stack backtrace:
1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
`RUST_BACKTRACE` also works with Cargo’s `run` command:
```text
-$ RUST_BACKTRACE=1 cargo run
+$ RUST_BACKTRACE=full cargo run
Running `target/debug/diverges`
thread 'main' panicked at 'This function never returns!', hello.rs:2
stack backtrace:
}
```
-Save the file, and go back to your terminal window. On Linux or OSX, enter the
+Save the file, and go back to your terminal window. On Linux or macOS, enter the
following commands:
```bash
If you come from a C or C++ background, you'll notice that this is similar to
`gcc` or `clang`. After compiling successfully, Rust should output a binary
-executable, which you can see on Linux or OSX by entering the `ls` command in
+executable, which you can see on Linux or macOS by entering the `ls` command in
your shell as follows:
```bash
### Enumerate
-When you need to keep track of how many times you already looped, you can use the `.enumerate()` function.
+When you need to keep track of how many times you have already looped, you can
+use the `.enumerate()` function.
#### On ranges:
So there is a lot going on here. We have introduced two new crates: [`syn`] and
[`quote`]. As you may have noticed, `input: TokenSteam` is immediately converted
to a `String`. This `String` is a string representation of the Rust code for which
-we are deriving `HelloWorld` for. At the moment, the only thing you can do with a
+we are deriving `HelloWorld`. At the moment, the only thing you can do with a
`TokenStream` is convert it to a string. A richer API will exist in the future.
So what we really need is to be able to _parse_ Rust code into something
Check out the [docs](https://docs.rs/syn/0.10.5/syn/struct.MacroInput.html),
there is some useful information there. We are able to get the name of the
type using `ast.ident`. The `quote!` macro lets us write up the Rust code
-that we wish to return and convert it into `Tokens`. `quote!` let's us use some
+that we wish to return and convert it into `Tokens`. `quote!` lets us use some
really cool templating mechanics; we simply write `#name` and `quote!` will
replace it with the variable named `name`. You can even do some repetition
similar to regular macros work. You should check out the
```
We've done it!
+
+## Custom Attributes
+
+In some cases it might make sense to allow users some kind of configuration.
+For example, the user might want to overwrite the name that is printed in the `hello_world()` method.
+
+This can be achieved with custom attributes:
+
+```rust,ignore
+#[derive(HelloWorld)]
+#[HelloWorldName = "the best Pancakes"]
+struct Pancakes;
+
+fn main() {
+ Pancakes::hello_world();
+}
+```
+
+If we try to compile this though, the compiler will respond with an error:
+
+```bash
+error: The attribute `HelloWorldName` is currently unknown to the compiler and may have meaning added to it in the future (see issue #29642)
+```
+
+The compiler needs to know that we're handling this attribute and to not respond with an error.
+This is done in the `hello-world-derive` crate by adding `attributes` to the `proc_macro_derive` attribute:
+
+```rust,ignore
+#[proc_macro_derive(HelloWorld, attributes(HelloWorldName))]
+pub fn hello_world(input: TokenStream) -> TokenStream
+```
+
+Multiple attributes can be specified that way.
+
+## Raising Errors
+
+Let's assume that we do not want to accept enums as input to our custom derive method.
+
+This condition can be easily checked with the help of `syn`.
+But how do we tell the user, that we do not accept enums?
+The idiomatic way to report errors in procedural macros is to panic:
+
+```rust,ignore
+fn impl_hello_world(ast: &syn::MacroInput) -> quote::Tokens {
+ let name = &ast.ident;
+ // Check if derive(HelloWorld) was specified for a struct
+ if let syn::Body::Struct(_) = ast.body {
+ // Yes, this is a struct
+ quote! {
+ impl HelloWorld for #name {
+ fn hello_world() {
+ println!("Hello, World! My name is {}", stringify!(#name));
+ }
+ }
+ }
+ } else {
+ //Nope. This is an Enum. We cannot handle these!
+ panic!("#[derive(HelloWorld)] is only defined for structs, not for enums!");
+ }
+}
+```
+
+If a user now tries to derive `HelloWorld` from an enum they will be greeted with following, hopefully helpful, error:
+
+```bash
+error: custom derive attribute panicked
+ --> src/main.rs
+ |
+ | #[derive(HelloWorld)]
+ | ^^^^^^^^^^
+ |
+ = help: message: #[derive(HelloWorld)] is only defined for structs, not for enums!
+```
you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,823`. That
number comes from 2<sup>30</sup>, the number of bytes in a gigabyte. [^gigabyte]
-[^gigabyte]: ‘Gigabyte’ can mean two things: 10^9, or 2^30. The SI standard resolved this by stating that ‘gigabyte’ is 10^9, and ‘gibibyte’ is 2^30. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here.
+[^gigabyte]: ‘Gigabyte’ can mean two things: 10<sup>9</sup>, or 2<sup>30</sup>. The IEC standard resolved this by stating that ‘gigabyte’ is 10<sup>9</sup>, and ‘gibibyte’ is 2<sup>30</sup>. However, very few people use this terminology, and rely on context to differentiate. We follow in that tradition here.
This memory is kind of like a giant array: addresses start at zero and go
up to the final number. So here’s a diagram of our first stack frame:
```text
bubble_up(heap, index):
let elem = heap[index]
- while index != 0 && element < heap[parent(index)]:
+ while index != 0 && elem < heap[parent(index)]:
heap[index] = heap[parent(index)]
index = parent(index)
heap[index] = elem
bubble_up(heap, index):
let elem = heap[index]
try:
- while index != 0 && element < heap[parent(index)]:
+ Â Â Â Â while index != 0 && elem < heap[parent(index)]:
heap[index] = heap[parent(index)]
index = parent(index)
finally:
* wraps a `*const T` for variance
* includes a `PhantomData<T>`
-* auto-derives Send/Sync as if T was contained
-* marks the pointer as NonZero for the null-pointer optimization
+* auto-derives `Send`/`Sync` as if T was contained
+* marks the pointer as `NonZero` for the null-pointer optimization
+
+## Table of `PhantomData` patterns
+
+Here’s a table of all the wonderful ways `PhantomData` could be used:
+
+| Phantom type | `'a` | `T` |
+|-----------------------------|-----------|---------------------------|
+| `PhantomData<T>` | - | variant (with drop check) |
+| `PhantomData<&'a T>` | variant | variant |
+| `PhantomData<&'a mut T>` | variant | invariant |
+| `PhantomData<*const T>` | - | variant |
+| `PhantomData<*mut T>` | - | invariant |
+| `PhantomData<fn(T)>` | - | contravariant (*) |
+| `PhantomData<fn() -> T>` | - | variant |
+| `PhantomData<fn(T) -> T>` | - | invariant |
+| `PhantomData<Cell<&'a ()>>` | invariant | - |
+
+(*) If contravariance gets scrapped, this would be invariant.
Rust code then checks for their presence using the `#[cfg(...)]` attribute:
```
-// The function is only included in the build when compiling for OSX
+// The function is only included in the build when compiling for macOS
#[cfg(target_os = "macos")]
fn macos_only() {
// ...
* `--crate-type=cdylib`, `#[crate_type = "cdylib"]` - A dynamic system
library will be produced. This is used when compiling Rust code as
a dynamic library to be loaded from another language. This output type will
- create `*.so` files on Linux, `*.dylib` files on OSX, and `*.dll` files on
+ create `*.so` files on Linux, `*.dylib` files on macOS, and `*.dll` files on
Windows.
* `--crate-type=rlib`, `#[crate_type = "rlib"]` - A "Rust library" file will be
//!
//! A format string is required to use all of its arguments, otherwise it is a
//! compile-time error. You may refer to the same argument more than once in the
-//! format string, although it must always be referred to with the same type.
+//! format string.
//!
//! ## Named parameters
//!
//!
//! ## Argument types
//!
-//! Each argument's type is dictated by the format string. It is a requirement
-//! that every argument is only ever referred to by one type. For example, this
-//! is an invalid format string:
-//!
-//! ```text
-//! {0:x} {0:o}
-//! ```
-//!
-//! This is invalid because the first argument is both referred to as a
-//! hexadecimal as well as an
-//! octal.
-//!
-//! There are various parameters which do require a particular type, however.
+//! Each argument's type is dictated by the format string.
+//! There are various parameters which require a particular type, however.
//! An example is the `{:.*}` syntax, which sets the number of decimal places
//! in floating-point types:
//!
//!
//! If this syntax is used, then the number of characters to print precedes the
//! actual object being formatted, and the number of characters must have the
-//! type `usize`. Although a `usize` can be printed with `{}`, it is invalid to
-//! reference an argument as such. For example this is another invalid format
-//! string:
-//!
-//! ```text
-//! {:.*} {0}
-//! ```
+//! type `usize`.
//!
//! ## Formatting traits
//!
/// If `new_len` is greater than the string's current length, this has no
/// effect.
///
+ /// Note that this method has no effect on the allocated capacity
+ /// of the string
+ ///
/// # Panics
///
/// Panics if `new_len` does not lie on a [`char`] boundary.
}
}
+/// Implements the `+` operator for concatenating two strings.
+///
+/// This consumes the `String` on the left-hand side and re-uses its buffer (growing it if
+/// necessary). This is done to avoid allocating a new `String` and copying the entire contents on
+/// every operation, which would lead to `O(n^2)` running time when building an `n`-byte string by
+/// repeated concatenation.
+///
+/// The string on the right-hand side is only borrowed; its contents are copied into the returned
+/// `String`.
+///
+/// # Examples
+///
+/// Concatenating two `String`s takes the first by value and borrows the second:
+///
+/// ```
+/// let a = String::from("hello");
+/// let b = String::from(" world");
+/// let c = a + &b;
+/// // `a` is moved and can no longer be used here.
+/// ```
+///
+/// If you want to keep using the first `String`, you can clone it and append to the clone instead:
+///
+/// ```
+/// let a = String::from("hello");
+/// let b = String::from(" world");
+/// let c = a.clone() + &b;
+/// // `a` is still valid here.
+/// ```
+///
+/// Concatenating `&str` slices can be done by converting the first to a `String`:
+///
+/// ```
+/// let a = "hello";
+/// let b = " world";
+/// let c = a.to_string() + b;
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Add<&'a str> for String {
type Output = String;
}
}
+/// Implements the `+=` operator for appending to a `String`.
+///
+/// This has the same behavior as the [`push_str()`] method.
+///
+/// [`push_str()`]: struct.String.html#method.push_str
#[stable(feature = "stringaddassign", since = "1.12.0")]
impl<'a> AddAssign<&'a str> for String {
#[inline]
/// The [`drain`] method can emulate `truncate`, but causes the excess
/// elements to be returned instead of dropped.
///
+ /// Note that this method has no effect on the allocated capacity
+ /// of the vector.
+ ///
/// # Examples
///
/// Truncating a five element vector to two elements:
/// Clears the vector, removing all values.
///
+ /// Note that this method has no effect on the allocated capacity
+ /// of the vector.
+ ///
/// # Examples
///
/// ```
30 31 32
}
+/// Implements comparison of vectors, lexicographically.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd> PartialOrd for Vec<T> {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq> Eq for Vec<T> {}
+/// Implements ordering of vectors, lexicographically.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Ord for Vec<T> {
#[inline]
// compiler-rt's build system already
cfg.flag("-fno-builtin");
cfg.flag("-fvisibility=hidden");
- cfg.flag("-fomit-frame-pointer");
+ // Accepted practice on Solaris is to never omit frame pointer so that
+ // system observability tools work as expected. In addition, at least
+ // on Solaris, -fomit-frame-pointer on sparcv9 appears to generate
+ // references to data outside of the current stack frame. A search of
+ // the gcc bug database provides a variety of issues surrounding
+ // -fomit-frame-pointer on non-x86 platforms.
+ if !target.contains("solaris") && !target.contains("sparc") {
+ cfg.flag("-fomit-frame-pointer");
+ }
cfg.flag("-ffreestanding");
cfg.define("VISIBILITY_HIDDEN", None);
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Eq> Eq for [T] {}
+/// Implements comparison of vectors lexicographically.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: Ord> Ord for [T] {
fn cmp(&self, other: &[T]) -> Ordering {
}
}
+/// Implements comparison of vectors lexicographically.
#[stable(feature = "rust1", since = "1.0.0")]
impl<T: PartialOrd> PartialOrd for [T] {
fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
use ops;
use str::eq_slice;
+ /// Implements ordering of strings.
+ ///
+ /// Strings are ordered lexicographically by their byte values. This orders Unicode code
+ /// points based on their positions in the code charts. This is not necessarily the same as
+ /// "alphabetical" order, which varies by language and locale. Sorting strings according to
+ /// culturally-accepted standards requires locale-specific data that is outside the scope of
+ /// the `str` type.
#[stable(feature = "rust1", since = "1.0.0")]
impl Ord for str {
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
impl Eq for str {}
+ /// Implements comparison operations on strings.
+ ///
+ /// Strings are compared lexicographically by their byte values. This compares Unicode code
+ /// points based on their positions in the code charts. This is not necessarily the same as
+ /// "alphabetical" order, which varies by language and locale. Comparing strings according to
+ /// culturally-accepted standards requires locale-specific data that is outside the scope of
+ /// the `str` type.
#[stable(feature = "rust1", since = "1.0.0")]
impl PartialOrd for str {
#[inline]
-Subproject commit 7a3754f2bb5e65eb39adacb189c3626173032177
+Subproject commit 64d954c6a76e896fbf7ed5c17e77c40e388abe84
// Note that `break` and `continue` statements
// may cause additional edges.
- // Is the condition considered part of the loop?
let loopback = self.add_dummy_node(&[pred]); // 1
- let cond_exit = self.expr(&cond, loopback); // 2
- let expr_exit = self.add_ast_node(expr.id, &[cond_exit]); // 3
+
+ // Create expr_exit without pred (cond_exit)
+ let expr_exit = self.add_ast_node(expr.id, &[]); // 3
+
+ // The LoopScope needs to be on the loop_scopes stack while evaluating the
+ // condition and the body of the loop (both can break out of the loop)
self.loop_scopes.push(LoopScope {
loop_id: expr.id,
continue_index: loopback,
break_index: expr_exit
});
+
+ let cond_exit = self.expr(&cond, loopback); // 2
+
+ // Add pred (cond_exit) to expr_exit
+ self.add_contained_edge(cond_exit, expr_exit);
+
let body_exit = self.block(&body, cond_exit); // 4
self.add_contained_edge(body_exit, loopback); // 5
self.loop_scopes.pop();
self.add_unreachable_node()
}
- hir::ExprBreak(label, ref opt_expr) => {
+ hir::ExprBreak(destination, ref opt_expr) => {
let v = self.opt_expr(opt_expr, pred);
- let loop_scope = self.find_scope(expr, label);
+ let loop_scope = self.find_scope(expr, destination);
let b = self.add_ast_node(expr.id, &[v]);
self.add_exiting_edge(expr, b,
loop_scope, loop_scope.break_index);
self.add_unreachable_node()
}
- hir::ExprAgain(label) => {
- let loop_scope = self.find_scope(expr, label);
+ hir::ExprAgain(destination) => {
+ let loop_scope = self.find_scope(expr, destination);
let a = self.add_ast_node(expr.id, &[pred]);
self.add_exiting_edge(expr, a,
loop_scope, loop_scope.continue_index);
fn find_scope(&self,
expr: &hir::Expr,
- label: Option<hir::Label>) -> LoopScope {
- match label {
- None => *self.loop_scopes.last().unwrap(),
- Some(label) => {
+ destination: hir::Destination) -> LoopScope {
+
+ match destination.loop_id.into() {
+ Ok(loop_id) => {
for l in &self.loop_scopes {
- if l.loop_id == label.loop_id {
+ if l.loop_id == loop_id {
return *l;
}
}
- span_bug!(expr.span, "no loop scope for id {}", label.loop_id);
+ span_bug!(expr.span, "no loop scope for id {}", loop_id);
}
+ Err(err) => span_bug!(expr.span, "loop scope error: {}", err)
}
}
}
Resolve,
EntryPoint,
CheckEntryFn,
+ CoherenceCheckTrait(D),
CoherenceCheckImpl(D),
CoherenceOverlapCheck(D),
CoherenceOverlapCheckSpecial(D),
// predicates for an item wind up in `ItemSignature`).
AssociatedItems(D),
ItemSignature(D),
+ TypeParamPredicates((D, D)),
SizedConstraint(D),
AssociatedItemDefIds(D),
InherentImpls(D),
TypeckTables(D),
UsedTraitImports(D),
+ MonomorphicConstEval(D),
// The set of impls for a given trait. Ultimately, it would be
// nice to get more fine-grained here (e.g., to include a
MetaData(ref d) => op(d).map(MetaData),
CollectItem(ref d) => op(d).map(CollectItem),
CollectItemSig(ref d) => op(d).map(CollectItemSig),
+ CoherenceCheckTrait(ref d) => op(d).map(CoherenceCheckTrait),
CoherenceCheckImpl(ref d) => op(d).map(CoherenceCheckImpl),
CoherenceOverlapCheck(ref d) => op(d).map(CoherenceOverlapCheck),
CoherenceOverlapCheckSpecial(ref d) => op(d).map(CoherenceOverlapCheckSpecial),
TransInlinedItem(ref d) => op(d).map(TransInlinedItem),
AssociatedItems(ref d) => op(d).map(AssociatedItems),
ItemSignature(ref d) => op(d).map(ItemSignature),
+ TypeParamPredicates((ref item, ref param)) => {
+ Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
+ }
SizedConstraint(ref d) => op(d).map(SizedConstraint),
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
InherentImpls(ref d) => op(d).map(InherentImpls),
TypeckTables(ref d) => op(d).map(TypeckTables),
UsedTraitImports(ref d) => op(d).map(UsedTraitImports),
+ MonomorphicConstEval(ref d) => op(d).map(MonomorphicConstEval),
TraitImpls(ref d) => op(d).map(TraitImpls),
TraitItems(ref d) => op(d).map(TraitItems),
ReprHints(ref d) => op(d).map(ReprHints),
use hir::def_id::DefId;
use rustc_data_structures::fx::FxHashMap;
use std::cell::RefCell;
+use std::collections::hash_map::Entry;
use std::ops::Index;
use std::hash::Hash;
use std::marker::PhantomData;
assert!(old_value.is_none());
}
+ pub fn entry(&mut self, k: M::Key) -> Entry<M::Key, M::Value> {
+ self.write(&k);
+ self.map.entry(k)
+ }
+
pub fn contains_key(&self, k: &M::Key) -> bool {
self.read(k);
self.map.contains_key(k)
[iss15872]: https://github.com/rust-lang/rust/issues/15872
"##,
-E0109: r##"
-You tried to give a type parameter to a type which doesn't need it. Erroneous
-code example:
-
-```compile_fail,E0109
-type X = u32<i32>; // error: type parameters are not allowed on this type
-```
-
-Please check that you used the correct type and recheck its definition. Perhaps
-it doesn't need the type parameter.
-
-Example:
-
-```
-type X = u32; // this compiles
-```
-
-Note that type parameters for enum-variant constructors go after the variant,
-not after the enum (Option::None::<u32>, not Option::<u32>::None).
-"##,
-
-E0110: r##"
-You tried to give a lifetime parameter to a type which doesn't need it.
-Erroneous code example:
-
-```compile_fail,E0110
-type X = u32<'static>; // error: lifetime parameters are not allowed on
- // this type
-```
-
-Please check that the correct type was used and recheck its definition; perhaps
-it doesn't need the lifetime parameter. Example:
-
-```
-type X = u32; // ok!
-```
-"##,
-
E0133: r##"
Unsafe code was used outside of an unsafe function or block.
See also https://doc.rust-lang.org/book/no-stdlib.html
"##,
-E0229: r##"
-An associated type binding was done outside of the type parameter declaration
-and `where` clause. Erroneous code example:
-
-```compile_fail,E0229
-pub trait Foo {
- type A;
- fn boo(&self) -> <Self as Foo>::A;
-}
-
-struct Bar;
-
-impl Foo for isize {
- type A = usize;
- fn boo(&self) -> usize { 42 }
-}
-
-fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
-// error: associated type bindings are not allowed here
-```
-
-To solve this error, please move the type bindings in the type parameter
-declaration:
-
-```ignore
-fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
-```
-
-Or in the `where` clause:
-
-```ignore
-fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
-```
-"##,
-
E0261: r##"
When using a lifetime like `'a` in a type, it must be declared before being
used.
block.
"##,
+E0391: r##"
+This error indicates that some types or traits depend on each other
+and therefore cannot be constructed.
+
+The following example contains a circular dependency between two traits:
+
+```compile_fail,E0391
+trait FirstTrait : SecondTrait {
+
+}
+
+trait SecondTrait : FirstTrait {
+
+}
+```
+"##,
+
E0398: r##"
In Rust 1.3, the default object lifetime bounds are expected to change, as
described in RFC #1156 [1]. You are getting a warning because the compiler
use hir::def_id::DefId;
use util::nodemap::NodeMap;
use syntax::ast;
+use syntax::ext::base::MacroKind;
use hir;
#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
Label(ast::NodeId),
// Macro namespace
- Macro(DefId),
+ Macro(DefId, MacroKind),
// Both namespaces
Err,
Def::Variant(id) | Def::VariantCtor(id, ..) | Def::Enum(id) | Def::TyAlias(id) |
Def::AssociatedTy(id) | Def::TyParam(id) | Def::Struct(id) | Def::StructCtor(id, ..) |
Def::Union(id) | Def::Trait(id) | Def::Method(id) | Def::Const(id) |
- Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id) => {
+ Def::AssociatedConst(id) | Def::Local(id) | Def::Upvar(id, ..) | Def::Macro(id, ..) => {
id
}
ExprPath(ref qpath) => {
visitor.visit_qpath(qpath, expression.id, expression.span);
}
- ExprBreak(None, ref opt_expr) => {
+ ExprBreak(label, ref opt_expr) => {
+ label.ident.map(|ident| {
+ if let Ok(loop_id) = label.loop_id.into() {
+ visitor.visit_def_mention(Def::Label(loop_id));
+ }
+ visitor.visit_name(ident.span, ident.node.name);
+ });
walk_list!(visitor, visit_expr, opt_expr);
}
- ExprBreak(Some(label), ref opt_expr) => {
- visitor.visit_def_mention(Def::Label(label.loop_id));
- visitor.visit_name(label.span, label.name);
- walk_list!(visitor, visit_expr, opt_expr);
- }
- ExprAgain(None) => {}
- ExprAgain(Some(label)) => {
- visitor.visit_def_mention(Def::Label(label.loop_id));
- visitor.visit_name(label.span, label.name);
+ ExprAgain(label) => {
+ label.ident.map(|ident| {
+ if let Ok(loop_id) = label.loop_id.into() {
+ visitor.visit_def_mention(Def::Label(loop_id));
+ }
+ visitor.visit_name(ident.span, ident.node.name);
+ });
}
ExprRet(ref optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
use std::collections::BTreeMap;
use std::iter;
+use std::mem;
use syntax::attr;
use syntax::ast::*;
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
bodies: FxHashMap<hir::BodyId, hir::Body>,
+ trait_impls: BTreeMap<DefId, Vec<NodeId>>,
+ trait_default_impl: BTreeMap<DefId, NodeId>,
+
+ loop_scopes: Vec<NodeId>,
+ is_in_loop_condition: bool,
+
type_def_lifetime_params: DefIdMap<usize>,
}
trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
bodies: FxHashMap(),
+ trait_impls: BTreeMap::new(),
+ trait_default_impl: BTreeMap::new(),
+ loop_scopes: Vec::new(),
+ is_in_loop_condition: false,
type_def_lifetime_params: DefIdMap(),
}.lower_crate(krate)
}
trait_items: self.trait_items,
impl_items: self.impl_items,
bodies: self.bodies,
+ trait_impls: self.trait_impls,
+ trait_default_impl: self.trait_default_impl,
}
}
span
}
+ fn with_loop_scope<T, F>(&mut self, loop_id: NodeId, f: F) -> T
+ where F: FnOnce(&mut LoweringContext) -> T
+ {
+ // We're no longer in the base loop's condition; we're in another loop.
+ let was_in_loop_condition = self.is_in_loop_condition;
+ self.is_in_loop_condition = false;
+
+ let len = self.loop_scopes.len();
+ self.loop_scopes.push(loop_id);
+
+ let result = f(self);
+ assert_eq!(len + 1, self.loop_scopes.len(),
+ "Loop scopes should be added and removed in stack order");
+
+ self.loop_scopes.pop().unwrap();
+
+ self.is_in_loop_condition = was_in_loop_condition;
+
+ result
+ }
+
+ fn with_loop_condition_scope<T, F>(&mut self, f: F) -> T
+ where F: FnOnce(&mut LoweringContext) -> T
+ {
+ let was_in_loop_condition = self.is_in_loop_condition;
+ self.is_in_loop_condition = true;
+
+ let result = f(self);
+
+ self.is_in_loop_condition = was_in_loop_condition;
+
+ result
+ }
+
+ fn with_new_loop_scopes<T, F>(&mut self, f: F) -> T
+ where F: FnOnce(&mut LoweringContext) -> T
+ {
+ let was_in_loop_condition = self.is_in_loop_condition;
+ self.is_in_loop_condition = false;
+
+ let loop_scopes = mem::replace(&mut self.loop_scopes, Vec::new());
+ let result = f(self);
+ mem::replace(&mut self.loop_scopes, loop_scopes);
+
+ self.is_in_loop_condition = was_in_loop_condition;
+
+ result
+ }
+
fn with_parent_def<T, F>(&mut self, parent_id: NodeId, f: F) -> T
where F: FnOnce(&mut LoweringContext) -> T
{
o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
}
- fn lower_label(&mut self, id: NodeId, label: Option<Spanned<Ident>>) -> Option<hir::Label> {
- label.map(|sp_ident| {
- hir::Label {
- span: sp_ident.span,
- name: sp_ident.node.name,
- loop_id: match self.expect_full_def(id) {
- Def::Label(loop_id) => loop_id,
- _ => DUMMY_NODE_ID
+ fn lower_destination(&mut self, destination: Option<(NodeId, Spanned<Ident>)>)
+ -> hir::Destination
+ {
+ match destination {
+ Some((id, label_ident)) => hir::Destination {
+ ident: Some(label_ident),
+ loop_id: if let Def::Label(loop_id) = self.expect_full_def(id) {
+ hir::LoopIdResult::Ok(loop_id)
+ } else {
+ hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
}
+ },
+ None => hir::Destination {
+ ident: None,
+ loop_id: self.loop_scopes.last().map(|innermost_loop_id| Ok(*innermost_loop_id))
+ .unwrap_or(Err(hir::LoopIdError::OutsideLoopScope)).into()
}
- })
+ }
}
fn lower_attrs(&mut self, attrs: &Vec<Attribute>) -> hir::HirVec<Attribute> {
return n;
}
assert!(!def_id.is_local());
- let (n, _) = self.sess.cstore.item_generics_own_param_counts(def_id);
+ let n = self.sess.cstore.item_generics_cloned(def_id).regions.len();
self.type_def_lifetime_params.insert(def_id, n);
n
});
self.record_body(value, None))
}
ItemKind::Fn(ref decl, unsafety, constness, abi, ref generics, ref body) => {
- let body = self.lower_block(body);
- let body = self.expr_block(body, ThinVec::new());
- let body_id = self.record_body(body, Some(decl));
- hir::ItemFn(self.lower_fn_decl(decl),
- self.lower_unsafety(unsafety),
- self.lower_constness(constness),
- abi,
- self.lower_generics(generics),
- body_id)
+ self.with_new_loop_scopes(|this| {
+ let body = this.lower_block(body);
+ let body = this.expr_block(body, ThinVec::new());
+ let body_id = this.record_body(body, Some(decl));
+ hir::ItemFn(this.lower_fn_decl(decl),
+ this.lower_unsafety(unsafety),
+ this.lower_constness(constness),
+ abi,
+ this.lower_generics(generics),
+ body_id)
+ })
}
ItemKind::Mod(ref m) => hir::ItemMod(self.lower_mod(m)),
ItemKind::ForeignMod(ref nm) => hir::ItemForeignMod(self.lower_foreign_mod(nm)),
hir::ItemUnion(vdata, self.lower_generics(generics))
}
ItemKind::DefaultImpl(unsafety, ref trait_ref) => {
+ let trait_ref = self.lower_trait_ref(trait_ref);
+
+ if let Def::Trait(def_id) = trait_ref.path.def {
+ self.trait_default_impl.insert(def_id, id);
+ }
+
hir::ItemDefaultImpl(self.lower_unsafety(unsafety),
- self.lower_trait_ref(trait_ref))
+ trait_ref)
}
ItemKind::Impl(unsafety, polarity, ref generics, ref ifce, ref ty, ref impl_items) => {
let new_impl_items = impl_items.iter()
.map(|item| self.lower_impl_item_ref(item))
.collect();
let ifce = ifce.as_ref().map(|trait_ref| self.lower_trait_ref(trait_ref));
+
+ if let Some(ref trait_ref) = ifce {
+ if let Def::Trait(def_id) = trait_ref.path.def {
+ self.trait_impls.entry(def_id).or_insert(vec![]).push(id);
+ }
+ }
+
hir::ItemImpl(self.lower_unsafety(unsafety),
self.lower_impl_polarity(polarity),
self.lower_generics(generics),
hir::ExprIf(P(self.lower_expr(cond)), self.lower_block(blk), else_opt)
}
ExprKind::While(ref cond, ref body, opt_ident) => {
- hir::ExprWhile(P(self.lower_expr(cond)), self.lower_block(body),
- self.lower_opt_sp_ident(opt_ident))
+ self.with_loop_scope(e.id, |this|
+ hir::ExprWhile(
+ this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
+ this.lower_block(body),
+ this.lower_opt_sp_ident(opt_ident)))
}
ExprKind::Loop(ref body, opt_ident) => {
- hir::ExprLoop(self.lower_block(body),
- self.lower_opt_sp_ident(opt_ident),
- hir::LoopSource::Loop)
+ self.with_loop_scope(e.id, |this|
+ hir::ExprLoop(this.lower_block(body),
+ this.lower_opt_sp_ident(opt_ident),
+ hir::LoopSource::Loop))
}
ExprKind::Match(ref expr, ref arms) => {
hir::ExprMatch(P(self.lower_expr(expr)),
hir::MatchSource::Normal)
}
ExprKind::Closure(capture_clause, ref decl, ref body, fn_decl_span) => {
- self.with_parent_def(e.id, |this| {
- let expr = this.lower_expr(body);
- hir::ExprClosure(this.lower_capture_clause(capture_clause),
- this.lower_fn_decl(decl),
- this.record_body(expr, Some(decl)),
- fn_decl_span)
+ self.with_new_loop_scopes(|this| {
+ this.with_parent_def(e.id, |this| {
+ let expr = this.lower_expr(body);
+ hir::ExprClosure(this.lower_capture_clause(capture_clause),
+ this.lower_fn_decl(decl),
+ this.record_body(expr, Some(decl)),
+ fn_decl_span)
+ })
})
}
ExprKind::Block(ref blk) => hir::ExprBlock(self.lower_block(blk)),
hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional))
}
ExprKind::Break(opt_ident, ref opt_expr) => {
- hir::ExprBreak(self.lower_label(e.id, opt_ident),
- opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
+ let label_result = if self.is_in_loop_condition && opt_ident.is_none() {
+ hir::Destination {
+ ident: opt_ident,
+ loop_id: Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
+ }
+ } else {
+ self.lower_destination(opt_ident.map(|ident| (e.id, ident)))
+ };
+ hir::ExprBreak(
+ label_result,
+ opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
}
- ExprKind::Continue(opt_ident) => hir::ExprAgain(self.lower_label(e.id, opt_ident)),
+ ExprKind::Continue(opt_ident) =>
+ hir::ExprAgain(
+ if self.is_in_loop_condition && opt_ident.is_none() {
+ hir::Destination {
+ ident: opt_ident,
+ loop_id: Err(
+ hir::LoopIdError::UnlabeledCfInWhileCondition).into(),
+ }
+ } else {
+ self.lower_destination(opt_ident.map( |ident| (e.id, ident)))
+ }),
ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
ExprKind::InlineAsm(ref asm) => {
let hir_asm = hir::InlineAsm {
// }
// }
+ // Note that the block AND the condition are evaluated in the loop scope.
+ // This is done to allow `break` from inside the condition of the loop.
+ let (body, break_expr, sub_expr) = self.with_loop_scope(e.id, |this| (
+ this.lower_block(body),
+ this.expr_break(e.span, ThinVec::new()),
+ this.with_loop_condition_scope(|this| P(this.lower_expr(sub_expr))),
+ ));
+
// `<pat> => <body>`
let pat_arm = {
- let body = self.lower_block(body);
let body_expr = P(self.expr_block(body, ThinVec::new()));
let pat = self.lower_pat(pat);
self.arm(hir_vec![pat], body_expr)
// `_ => break`
let break_arm = {
let pat_under = self.pat_wild(e.span);
- let break_expr = self.expr_break(e.span, ThinVec::new());
self.arm(hir_vec![pat_under], break_expr)
};
// `match <sub_expr> { ... }`
let arms = hir_vec![pat_arm, break_arm];
- let sub_expr = P(self.lower_expr(sub_expr));
let match_expr = self.expr(e.span,
hir::ExprMatch(sub_expr,
arms,
// `::std::option::Option::Some(<pat>) => <body>`
let pat_arm = {
- let body_block = self.lower_block(body);
+ let body_block = self.with_loop_scope(e.id, |this| this.lower_block(body));
let body_expr = P(self.expr_block(body_block, ThinVec::new()));
let pat = self.lower_pat(pat);
let some_pat = self.pat_some(e.span, pat);
// `::std::option::Option::None => break`
let break_arm = {
- let break_expr = self.expr_break(e.span, ThinVec::new());
+ let break_expr = self.with_loop_scope(e.id, |this|
+ this.expr_break(e.span, ThinVec::new()));
let pat = self.pat_none(e.span);
self.arm(hir_vec![pat], break_expr)
};
}
fn expr_break(&mut self, span: Span, attrs: ThinVec<Attribute>) -> P<hir::Expr> {
- P(self.expr(span, hir::ExprBreak(None, None), attrs))
+ let expr_break = hir::ExprBreak(self.lower_destination(None), None);
+ P(self.expr(span, expr_break, attrs))
}
fn expr_call(&mut self, span: Span, e: P<hir::Expr>, args: hir::HirVec<hir::Expr>)
self.local_def_id(self.body_owner(id))
}
+ pub fn ty_param_owner(&self, id: NodeId) -> NodeId {
+ match self.get(id) {
+ NodeItem(&Item { node: ItemTrait(..), .. }) => id,
+ NodeTyParam(_) => self.get_parent_node(id),
+ _ => {
+ bug!("ty_param_owner: {} not a type parameter",
+ self.node_to_string(id))
+ }
+ }
+ }
+
+ pub fn ty_param_name(&self, id: NodeId) -> Name {
+ match self.get(id) {
+ NodeItem(&Item { node: ItemTrait(..), .. }) => {
+ keywords::SelfType.name()
+ }
+ NodeTyParam(tp) => tp.name,
+ _ => {
+ bug!("ty_param_name: {} not a type parameter",
+ self.node_to_string(id))
+ }
+ }
+ }
+
+ pub fn trait_impls(&self, trait_did: DefId) -> &'hir [NodeId] {
+ self.dep_graph.read(DepNode::TraitImpls(trait_did));
+
+ // NB: intentionally bypass `self.forest.krate()` so that we
+ // do not trigger a read of the whole krate here
+ self.forest.krate.trait_impls.get(&trait_did).map_or(&[], |xs| &xs[..])
+ }
+
+ pub fn trait_default_impl(&self, trait_did: DefId) -> Option<NodeId> {
+ self.dep_graph.read(DepNode::TraitImpls(trait_did));
+
+ // NB: intentionally bypass `self.forest.krate()` so that we
+ // do not trigger a read of the whole krate here
+ self.forest.krate.trait_default_impl.get(&trait_did).cloned()
+ }
+
+ pub fn trait_is_auto(&self, trait_did: DefId) -> bool {
+ self.trait_default_impl(trait_did).is_some()
+ }
+
/// Get the attributes on the krate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
use syntax_pos::{Span, ExpnId, DUMMY_SP};
use syntax::codemap::{self, Spanned};
use syntax::abi::Abi;
-use syntax::ast::{Name, NodeId, DUMMY_NODE_ID, AsmDialect};
+use syntax::ast::{Ident, Name, NodeId, DUMMY_NODE_ID, AsmDialect};
use syntax::ast::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
use syntax::ptr::P;
use syntax::symbol::{Symbol, keywords};
pub trait_items: BTreeMap<TraitItemId, TraitItem>,
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
pub bodies: FxHashMap<BodyId, Body>,
+
+ pub trait_impls: BTreeMap<DefId, Vec<NodeId>>,
+ pub trait_default_impl: BTreeMap<DefId, NodeId>,
}
impl Crate {
/// A referencing operation (`&a` or `&mut a`)
ExprAddrOf(Mutability, P<Expr>),
/// A `break`, with an optional label to break
- ExprBreak(Option<Label>, Option<P<Expr>>),
+ ExprBreak(Destination, Option<P<Expr>>),
/// A `continue`, with an optional label
- ExprAgain(Option<Label>),
+ ExprAgain(Destination),
/// A `return`, with an optional value to be returned
ExprRet(Option<P<Expr>>),
ForLoop,
}
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub enum LoopIdError {
+ OutsideLoopScope,
+ UnlabeledCfInWhileCondition,
+ UnresolvedLabel,
+}
+impl fmt::Display for LoopIdError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(match *self {
+ LoopIdError::OutsideLoopScope => "not inside loop scope",
+ LoopIdError::UnlabeledCfInWhileCondition =>
+ "unlabeled control flow (break or continue) in while condition",
+ LoopIdError::UnresolvedLabel => "label not found",
+ }, f)
+ }
+}
+
+// FIXME(cramertj) this should use `Result` once master compiles w/ a vesion of Rust where
+// `Result` implements `Encodable`/`Decodable`
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub struct Label {
- pub span: Span,
- pub name: Name,
- pub loop_id: NodeId
+pub enum LoopIdResult {
+ Ok(NodeId),
+ Err(LoopIdError),
+}
+impl Into<Result<NodeId, LoopIdError>> for LoopIdResult {
+ fn into(self) -> Result<NodeId, LoopIdError> {
+ match self {
+ LoopIdResult::Ok(ok) => Ok(ok),
+ LoopIdResult::Err(err) => Err(err),
+ }
+ }
+}
+impl From<Result<NodeId, LoopIdError>> for LoopIdResult {
+ fn from(res: Result<NodeId, LoopIdError>) -> Self {
+ match res {
+ Ok(ok) => LoopIdResult::Ok(ok),
+ Err(err) => LoopIdResult::Err(err),
+ }
+ }
+}
+
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
+pub struct Destination {
+ // This is `Some(_)` iff there is an explicit user-specified `label
+ pub ident: Option<Spanned<Ident>>,
+
+ // These errors are caught and then reported during the diagnostics pass in
+ // librustc_passes/loops.rs
+ pub loop_id: LoopIdResult,
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
hir::ExprPath(ref qpath) => {
self.print_qpath(qpath, true)?
}
- hir::ExprBreak(opt_label, ref opt_expr) => {
+ hir::ExprBreak(label, ref opt_expr) => {
word(&mut self.s, "break")?;
space(&mut self.s)?;
- if let Some(label) = opt_label {
- self.print_name(label.name)?;
+ if let Some(label_ident) = label.ident {
+ self.print_name(label_ident.node.name)?;
space(&mut self.s)?;
}
if let Some(ref expr) = *opt_expr {
space(&mut self.s)?;
}
}
- hir::ExprAgain(opt_label) => {
+ hir::ExprAgain(label) => {
word(&mut self.s, "continue")?;
space(&mut self.s)?;
- if let Some(label) = opt_label {
- self.print_name(label.name)?;
+ if let Some(label_ident) = label.ident {
+ self.print_name(label_ident.node.name)?;
space(&mut self.s)?
}
}
values: Option<ValuePairs<'tcx>>,
terr: &TypeError<'tcx>)
{
- let expected_found = match values {
- None => None,
- Some(values) => match self.values_str(&values) {
- Some((expected, found)) => Some((expected, found)),
- None => {
- // Derived error. Cancel the emitter.
- self.tcx.sess.diagnostic().cancel(diag);
- return
- }
+ let (expected_found, is_simple_error) = match values {
+ None => (None, false),
+ Some(values) => {
+ let is_simple_error = match values {
+ ValuePairs::Types(exp_found) => {
+ exp_found.expected.is_primitive() && exp_found.found.is_primitive()
+ }
+ _ => false,
+ };
+ let vals = match self.values_str(&values) {
+ Some((expected, found)) => Some((expected, found)),
+ None => {
+ // Derived error. Cancel the emitter.
+ self.tcx.sess.diagnostic().cancel(diag);
+ return
+ }
+ };
+ (vals, is_simple_error)
}
};
let span = cause.span;
if let Some((expected, found)) = expected_found {
- let is_simple_error = if let &TypeError::Sorts(ref values) = terr {
- values.expected.is_primitive() && values.found.is_primitive()
- } else {
- false
- };
-
- if !is_simple_error {
- if expected == found {
- if let &TypeError::Sorts(ref values) = terr {
- diag.note_expected_found_extra(
- &"type", &expected, &found,
- &format!(" ({})", values.expected.sort_string(self.tcx)),
- &format!(" ({})", values.found.sort_string(self.tcx)));
- } else {
- diag.note_expected_found(&"type", &expected, &found);
- }
- } else {
+ match (terr, is_simple_error, expected == found) {
+ (&TypeError::Sorts(ref values), false, true) => {
+ diag.note_expected_found_extra(
+ &"type", &expected, &found,
+ &format!(" ({})", values.expected.sort_string(self.tcx)),
+ &format!(" ({})", values.found.sort_string(self.tcx)));
+ }
+ (_, false, _) => {
diag.note_expected_found(&"type", &expected, &found);
}
+ _ => (),
}
}
evaluation_cache: traits::EvaluationCache::new(),
projection_cache: RefCell::new(traits::ProjectionCache::new()),
reported_trait_errors: RefCell::new(FxHashSet()),
- projection_mode: Reveal::NotSpecializable,
+ projection_mode: Reveal::UserFacing,
tainted_by_errors_flag: Cell::new(false),
err_count_on_creation: self.sess.err_count(),
obligations_in_snapshot: Cell::new(false),
Ty<'gcx>,
&'gcx Substs<'gcx>,
ty::FnSig<'gcx>,
- &'gcx ty::BareFnTy<'gcx>,
+ ty::PolyFnSig<'gcx>,
ty::ClosureSubsts<'gcx>,
ty::PolyTraitRef<'gcx>,
ty::ExistentialTraitRef<'gcx>
/// as the substitutions for the default, `(T, U)`.
pub fn type_var_for_def(&self,
span: Span,
- def: &ty::TypeParameterDef<'tcx>,
+ def: &ty::TypeParameterDef,
substs: &[Kind<'tcx>])
-> Ty<'tcx> {
- let default = def.default.map(|default| {
- type_variable::Default {
+ let default = if def.has_default {
+ let default = self.tcx.item_type(def.def_id);
+ Some(type_variable::Default {
ty: default.subst_spanned(self.tcx, substs, Some(span)),
origin_span: span,
- def_id: def.default_def_id
- }
- });
+ def_id: def.def_id
+ })
+ } else {
+ None
+ };
let ty_var_id = self.type_variables
Some(self.tcx.closure_kind(def_id))
}
- pub fn closure_type(&self,
- def_id: DefId,
- substs: ty::ClosureSubsts<'tcx>)
- -> ty::ClosureTy<'tcx>
- {
+ pub fn closure_type(&self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
if let InferTables::InProgress(tables) = self.tables {
if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
- if let Some(ty) = tables.borrow().closure_tys.get(&id) {
- return ty.subst(self.tcx, substs.substs);
+ if let Some(&ty) = tables.borrow().closure_tys.get(&id) {
+ return ty;
}
}
}
- self.tcx.closure_type(def_id, substs)
+ self.tcx.closure_type(def_id)
}
}
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(slice_patterns)]
+#![feature(specialization)]
#![feature(staged_api)]
#![feature(unboxed_closures)]
pub mod lint;
pub mod middle {
- pub mod astconv_util;
pub mod expr_use_visitor;
pub mod const_val;
pub mod cstore;
+++ /dev/null
-// Copyright 2012-2014 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 module contains a simple utility routine
- * used by both `typeck` and `const_eval`.
- * Almost certainly this could (and should) be refactored out of existence.
- */
-
-use hir;
-use hir::def::Def;
-use ty::{Ty, TyCtxt};
-
-use syntax_pos::Span;
-
-impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
- pub fn prohibit_type_params(self, segments: &[hir::PathSegment]) {
- for segment in segments {
- for typ in segment.parameters.types() {
- struct_span_err!(self.sess, typ.span, E0109,
- "type parameters are not allowed on this type")
- .span_label(typ.span, &format!("type parameter not allowed"))
- .emit();
- break;
- }
- for lifetime in segment.parameters.lifetimes() {
- struct_span_err!(self.sess, lifetime.span, E0110,
- "lifetime parameters are not allowed on this type")
- .span_label(lifetime.span,
- &format!("lifetime parameter not allowed on this type"))
- .emit();
- break;
- }
- for binding in segment.parameters.bindings() {
- self.prohibit_projection(binding.span);
- break;
- }
- }
- }
-
- pub fn prohibit_projection(self, span: Span)
- {
- let mut err = struct_span_err!(self.sess, span, E0229,
- "associated type bindings are not allowed here");
- err.span_label(span, &format!("associate type not allowed here")).emit();
- }
-
- pub fn prim_ty_to_ty(self,
- segments: &[hir::PathSegment],
- nty: hir::PrimTy)
- -> Ty<'tcx> {
- self.prohibit_type_params(segments);
- match nty {
- hir::TyBool => self.types.bool,
- hir::TyChar => self.types.char,
- hir::TyInt(it) => self.mk_mach_int(it),
- hir::TyUint(uit) => self.mk_mach_uint(uit),
- hir::TyFloat(ft) => self.mk_mach_float(ft),
- hir::TyStr => self.mk_str()
- }
- }
-
- /// If a type in the AST is a primitive type, return the ty::Ty corresponding
- /// to it.
- pub fn ast_ty_to_prim_ty(self, ast_ty: &hir::Ty) -> Option<Ty<'tcx>> {
- if let hir::TyPath(hir::QPath::Resolved(None, ref path)) = ast_ty.node {
- if let Def::PrimTy(nty) = path.def {
- Some(self.prim_ty_to_ty(&path.segments, nty))
- } else {
- None
- }
- } else {
- None
- }
- }
-}
use syntax::ast;
use std::rc::Rc;
use hir::def_id::DefId;
+use ty::subst::Substs;
use rustc_const_math::*;
+
use self::ConstVal::*;
pub use rustc_const_math::ConstInt;
use std::collections::BTreeMap;
#[derive(Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
-pub enum ConstVal {
+pub enum ConstVal<'tcx> {
Float(ConstFloat),
Integral(ConstInt),
Str(InternedString),
ByteStr(Rc<Vec<u8>>),
Bool(bool),
- Function(DefId),
- Struct(BTreeMap<ast::Name, ConstVal>),
- Tuple(Vec<ConstVal>),
- Array(Vec<ConstVal>),
- Repeat(Box<ConstVal>, u64),
+ Function(DefId, &'tcx Substs<'tcx>),
+ Struct(BTreeMap<ast::Name, ConstVal<'tcx>>),
+ Tuple(Vec<ConstVal<'tcx>>),
+ Array(Vec<ConstVal<'tcx>>),
+ Repeat(Box<ConstVal<'tcx>>, u64),
Char(char),
}
-impl ConstVal {
+impl<'tcx> ConstVal<'tcx> {
pub fn description(&self) -> &'static str {
match *self {
Float(f) => f.description(),
Bool(_) => "boolean",
Struct(_) => "struct",
Tuple(_) => "tuple",
- Function(_) => "function definition",
+ Function(..) => "function definition",
Array(..) => "array",
Repeat(..) => "repeat",
Char(..) => "char",
pub fn to_const_int(&self) -> Option<ConstInt> {
match *self {
ConstVal::Integral(i) => Some(i),
- ConstVal::Bool(true) => Some(ConstInt::Infer(1)),
- ConstVal::Bool(false) => Some(ConstInt::Infer(0)),
+ ConstVal::Bool(b) => Some(ConstInt::U8(b as u8)),
ConstVal::Char(ch) => Some(ConstInt::U32(ch as u32)),
_ => None
}
use hir::map::definitions::{Definitions, DefKey, DisambiguatedDefPathData};
use hir::svh::Svh;
use middle::lang_items;
-use middle::resolve_lifetime::ObjectLifetimeDefault;
-use ty::{self, Ty, TyCtxt};
-use mir::Mir;
+use ty::{self, TyCtxt};
use session::Session;
use session::search_paths::PathKind;
use util::nodemap::{NodeSet, DefIdMap};
+use std::any::Any;
use std::collections::BTreeMap;
use std::path::PathBuf;
use std::rc::Rc;
/// A store of Rust crates, through with their metadata
/// can be accessed.
-pub trait CrateStore<'tcx> {
+pub trait CrateStore {
+ fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>;
+
// item info
fn describe_def(&self, def: DefId) -> Option<Def>;
fn def_span(&self, sess: &Session, def: DefId) -> Span;
fn stability(&self, def: DefId) -> Option<attr::Stability>;
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation>;
fn visibility(&self, def: DefId) -> ty::Visibility;
- fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind;
- fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
- -> ty::ClosureTy<'tcx>;
- fn item_variances(&self, def: DefId) -> Vec<ty::Variance>;
- fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Ty<'tcx>;
fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>>;
- fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> ty::GenericPredicates<'tcx>;
- fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> ty::GenericPredicates<'tcx>;
- fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> ty::Generics<'tcx>;
- fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize);
- fn item_generics_object_lifetime_defaults(&self, def: DefId)
- -> Vec<ObjectLifetimeDefault>;
+ fn item_generics_cloned(&self, def: DefId) -> ty::Generics;
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>;
- fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef;
- fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef;
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>;
fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId>;
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId>;
// impl info
- fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>;
- fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<ty::TraitRef<'tcx>>;
fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity;
- fn custom_coerce_unsized_kind(&self, def: DefId)
- -> Option<ty::adjustment::CustomCoerceUnsized>;
fn impl_parent(&self, impl_def_id: DefId) -> Option<DefId>;
// trait/impl-item info
fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
- fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>;
+ fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem;
// flags
fn is_const_fn(&self, did: DefId) -> bool;
- fn is_defaulted_trait(&self, did: DefId) -> bool;
fn is_default_impl(&self, impl_did: DefId) -> bool;
fn is_foreign_item(&self, did: DefId) -> bool;
fn is_dllimport_foreign_item(&self, def: DefId) -> bool;
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
// misc. metadata
- fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<&'tcx hir::Body>;
+ fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+ -> Option<&'tcx hir::Body>;
fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body>;
fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool;
- fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx>;
fn is_item_mir_available(&self, def: DefId) -> bool;
// This is basically a 1-based range of ints, which is a little
fn used_crates(&self, prefer: LinkagePreference) -> Vec<(CrateNum, LibSource)>;
fn used_crate_source(&self, cnum: CrateNum) -> CrateSource;
fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum>;
- fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
- reexports: &def::ExportMap,
- link_meta: &LinkMeta,
- reachable: &NodeSet) -> Vec<u8>;
+ fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ reexports: &def::ExportMap,
+ link_meta: &LinkMeta,
+ reachable: &NodeSet) -> Vec<u8>;
fn metadata_encoding_version(&self) -> &[u8];
}
/// A dummy crate store that does not support any non-local crates,
/// for test purposes.
pub struct DummyCrateStore;
+
#[allow(unused_variables)]
-impl<'tcx> CrateStore<'tcx> for DummyCrateStore {
+impl CrateStore for DummyCrateStore {
+ fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any>
+ { bug!("crate_data_as_rc_any") }
// item info
fn describe_def(&self, def: DefId) -> Option<Def> { bug!("describe_def") }
fn def_span(&self, sess: &Session, def: DefId) -> Span { bug!("def_span") }
fn stability(&self, def: DefId) -> Option<attr::Stability> { bug!("stability") }
fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> { bug!("deprecation") }
fn visibility(&self, def: DefId) -> ty::Visibility { bug!("visibility") }
- fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind { bug!("closure_kind") }
- fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
- -> ty::ClosureTy<'tcx> { bug!("closure_ty") }
- fn item_variances(&self, def: DefId) -> Vec<ty::Variance> { bug!("item_variances") }
- fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Ty<'tcx> { bug!("item_type") }
fn visible_parent_map<'a>(&'a self) -> ::std::cell::RefMut<'a, DefIdMap<DefId>> {
bug!("visible_parent_map")
}
- fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> ty::GenericPredicates<'tcx> { bug!("item_predicates") }
- fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> ty::GenericPredicates<'tcx> { bug!("item_super_predicates") }
- fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> ty::Generics<'tcx> { bug!("item_generics") }
- fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize)
- { bug!("item_generics_own_param_counts") }
- fn item_generics_object_lifetime_defaults(&self, def: DefId)
- -> Vec<ObjectLifetimeDefault>
- { bug!("item_generics_object_lifetime_defaults") }
+ fn item_generics_cloned(&self, def: DefId) -> ty::Generics
+ { bug!("item_generics_cloned") }
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute> { bug!("item_attrs") }
- fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)-> ty::TraitDef
- { bug!("trait_def") }
- fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef
- { bug!("adt_def") }
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name> { bug!("fn_arg_names") }
fn inherent_implementations_for_type(&self, def_id: DefId) -> Vec<DefId> { vec![] }
fn implementations_of_trait(&self, filter: Option<DefId>) -> Vec<DefId> { vec![] }
// impl info
- fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId>
- { bug!("associated_items") }
- fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<ty::TraitRef<'tcx>> { bug!("impl_trait_ref") }
fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity { bug!("impl_polarity") }
- fn custom_coerce_unsized_kind(&self, def: DefId)
- -> Option<ty::adjustment::CustomCoerceUnsized>
- { bug!("custom_coerce_unsized_kind") }
fn impl_parent(&self, def: DefId) -> Option<DefId> { bug!("impl_parent") }
// trait/impl-item info
fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
- fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem> { bug!("associated_item") }
+ fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
+ { bug!("associated_item_cloned") }
// flags
fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
- fn is_defaulted_trait(&self, did: DefId) -> bool { bug!("is_defaulted_trait") }
fn is_default_impl(&self, impl_did: DefId) -> bool { bug!("is_default_impl") }
fn is_foreign_item(&self, did: DefId) -> bool { bug!("is_foreign_item") }
fn is_dllimport_foreign_item(&self, id: DefId) -> bool { false }
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
// misc. metadata
- fn maybe_get_item_body<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<&'tcx hir::Body> {
+ fn maybe_get_item_body<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
+ -> Option<&'tcx hir::Body> {
bug!("maybe_get_item_body")
}
fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
bug!("const_is_rvalue_promotable_to_static")
}
- fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Mir<'tcx> { bug!("get_item_mir") }
fn is_item_mir_available(&self, def: DefId) -> bool {
bug!("is_item_mir_available")
}
{ vec![] }
fn used_crate_source(&self, cnum: CrateNum) -> CrateSource { bug!("used_crate_source") }
fn extern_mod_stmt_cnum(&self, emod_id: ast::NodeId) -> Option<CrateNum> { None }
- fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
reexports: &def::ExportMap,
link_meta: &LinkMeta,
reachable: &NodeSet) -> Vec<u8> { vec![] }
hir_map::NodeItem(item) => {
match item.node {
hir::ItemStruct(..) | hir::ItemUnion(..) => {
- self.struct_has_extern_repr = item.attrs.iter().any(|attr| {
- attr::find_repr_attrs(self.tcx.sess.diagnostic(), attr)
- .contains(&attr::ReprExtern)
- });
+ let def_id = self.tcx.hir.local_def_id(item.id);
+ let def = self.tcx.lookup_adt_def(def_id);
+ self.struct_has_extern_repr = def.repr.c;
intravisit::walk_item(self, &item);
}
// method of a private type is used, but the type itself is never
// called directly.
if let Some(impl_list) =
- self.tcx.inherent_impls.borrow().get(&self.tcx.hir.local_def_id(id)) {
+ self.tcx.maps.inherent_impls.borrow().get(&self.tcx.hir.local_def_id(id)) {
for &impl_did in impl_list.iter() {
for &item_did in &self.tcx.associated_item_def_ids(impl_did)[..] {
if let Some(item_node_id) = self.tcx.hir.as_local_node_id(item_did) {
fn type_is_unsafe_function(ty: Ty) -> bool {
match ty.sty {
- ty::TyFnDef(.., ref f) |
- ty::TyFnPtr(ref f) => f.unsafety == hir::Unsafety::Unsafe,
+ ty::TyFnDef(.., f) |
+ ty::TyFnPtr(f) => f.unsafety() == hir::Unsafety::Unsafe,
_ => false,
}
}
adjustment::Adjust::NeverToAny |
adjustment::Adjust::ReifyFnPointer |
adjustment::Adjust::UnsafeFnPointer |
+ adjustment::Adjust::ClosureFnPointer |
adjustment::Adjust::MutToConstPointer => {
// Creating a closure/fn-pointer or unsizing consumes
// the input and stores it into the resulting rvalue.
impl<'a, 'gcx, 'tcx> ExprVisitor<'a, 'gcx, 'tcx> {
fn def_id_is_transmute(&self, def_id: DefId) -> bool {
let intrinsic = match self.infcx.tcx.item_type(def_id).sty {
- ty::TyFnDef(.., ref bfty) => bfty.abi == RustIntrinsic,
+ ty::TyFnDef(.., bfty) => bfty.abi() == RustIntrinsic,
_ => return false
};
intrinsic && self.infcx.tcx.item_name(def_id) == "transmute"
let typ = self.infcx.tables.borrow().node_id_to_type(expr.id);
let typ = self.infcx.tcx.lift_to_global(&typ).unwrap();
match typ.sty {
- ty::TyFnDef(.., ref bare_fn_ty) if bare_fn_ty.abi == RustIntrinsic => {
- let from = bare_fn_ty.sig.skip_binder().inputs()[0];
- let to = bare_fn_ty.sig.skip_binder().output();
+ ty::TyFnDef(.., sig) if sig.abi() == RustIntrinsic => {
+ let from = sig.inputs().skip_binder()[0];
+ let to = *sig.output().skip_binder();
self.check_transmute(expr.span, from, to, expr.id);
}
_ => {
Ok(())
}
- fn find_loop_scope(&self,
- opt_label: Option<hir::Label>,
- sp: Span)
- -> NodeId {
- match opt_label {
- Some(label) => label.loop_id,
- None => {
- // Vanilla 'break' or 'continue', so use the enclosing
- // loop scope
- if self.loop_scope.is_empty() {
- span_bug!(sp, "break outside loop");
- } else {
- *self.loop_scope.last().unwrap()
- }
- }
- }
- }
#[allow(unused_must_use)]
fn ln_str(&self, ln: LiveNode) -> String {
self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln)
}
- hir::ExprBreak(opt_label, ref opt_expr) => {
+ hir::ExprBreak(label, ref opt_expr) => {
// Find which label this break jumps to
- let sc = self.find_loop_scope(opt_label, expr.span);
+ let sc = match label.loop_id.into() {
+ Ok(loop_id) => loop_id,
+ Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
+ };
// Now that we know the label we're going to,
// look it up in the break loop nodes table
}
}
- hir::ExprAgain(opt_label) => {
+ hir::ExprAgain(label) => {
// Find which label this expr continues to
- let sc = self.find_loop_scope(opt_label, expr.span);
+ let sc = match label.loop_id.into() {
+ Ok(loop_id) => loop_id,
+ Err(err) => span_bug!(expr.span, "loop scope error: {}", err),
+ };
+
// Now that we know the label we're going to,
// look it up in the continue loop nodes table
debug!("propagate_through_loop: using id for loop body {} {}",
expr.id, self.ir.tcx.hir.node_to_pretty_string(body.id));
- let cond_ln = match kind {
- LoopLoop => ln,
- WhileLoop(ref cond) => self.propagate_through_expr(&cond, ln),
- };
- let body_ln = self.with_loop_nodes(expr.id, succ, ln, |this| {
- this.propagate_through_block(body, cond_ln)
+ let (cond_ln, body_ln) = self.with_loop_nodes(expr.id, succ, ln, |this| {
+ let cond_ln = match kind {
+ LoopLoop => ln,
+ WhileLoop(ref cond) => this.propagate_through_expr(&cond, ln),
+ };
+ let body_ln = this.propagate_through_block(body, cond_ln);
+ (cond_ln, body_ln)
});
// repeat until fixed point is reached:
body: &hir::Body)
{
let fn_ty = self.ir.tcx.item_type(self.ir.tcx.hir.local_def_id(id));
- let fn_ret = match fn_ty.sty {
- ty::TyClosure(closure_def_id, substs) =>
- self.ir.tcx.closure_type(closure_def_id, substs).sig.output(),
- _ => fn_ty.fn_ret()
+ let fn_sig = match fn_ty.sty {
+ ty::TyClosure(closure_def_id, substs) => {
+ self.ir.tcx.closure_type(closure_def_id)
+ .subst(self.ir.tcx, substs.substs)
+ }
+ _ => fn_ty.fn_sig()
};
+ let fn_ret = fn_sig.output();
+
// within the fn body, late-bound regions are liberated
// and must outlive the *call-site* of the function.
let fn_ret =
adjustment::Adjust::NeverToAny |
adjustment::Adjust::ReifyFnPointer |
adjustment::Adjust::UnsafeFnPointer |
+ adjustment::Adjust::ClosureFnPointer |
adjustment::Adjust::MutToConstPointer |
adjustment::Adjust::DerefRef {..} => {
debug!("cat_expr({:?}): {:?}",
} else {
let cstore = &self.sess.cstore;
self.xcrate_object_lifetime_defaults.entry(def_id).or_insert_with(|| {
- cstore.item_generics_object_lifetime_defaults(def_id)
+ cstore.item_generics_cloned(def_id).types.into_iter().map(|def| {
+ def.object_lifetime_default
+ }).collect()
})
};
unsubst.iter().map(|set| {
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
// (See issue #38412)
- fn skip_stability_check_due_to_privacy(self, def_id: DefId) -> bool {
- let visibility = {
- // Check if `def_id` is a trait method.
- match self.sess.cstore.associated_item(def_id) {
- Some(ty::AssociatedItem { container: ty::TraitContainer(trait_def_id), .. }) => {
- // Trait methods do not declare visibility (even
- // for visibility info in cstore). Use containing
- // trait instead, so methods of pub traits are
- // themselves considered pub.
- self.sess.cstore.visibility(trait_def_id)
- }
- _ => {
- // Otherwise, cstore info works directly.
- self.sess.cstore.visibility(def_id)
+ fn skip_stability_check_due_to_privacy(self, mut def_id: DefId) -> bool {
+ // Check if `def_id` is a trait method.
+ match self.sess.cstore.describe_def(def_id) {
+ Some(Def::Method(_)) |
+ Some(Def::AssociatedTy(_)) |
+ Some(Def::AssociatedConst(_)) => {
+ match self.associated_item(def_id).container {
+ ty::TraitContainer(trait_def_id) => {
+ // Trait methods do not declare visibility (even
+ // for visibility info in cstore). Use containing
+ // trait instead, so methods of pub traits are
+ // themselves considered pub.
+ def_id = trait_def_id;
+ }
+ _ => {}
}
}
- };
+ _ => {}
+ }
+
+ let visibility = self.sess.cstore.visibility(def_id);
match visibility {
// must check stability for pub items.
impl<'tcx> TerminatorKind<'tcx> {
pub fn if_<'a, 'gcx>(tcx: ty::TyCtxt<'a, 'gcx, 'tcx>, cond: Operand<'tcx>,
t: BasicBlock, f: BasicBlock) -> TerminatorKind<'tcx> {
- static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::Infer(0)];
+ static BOOL_SWITCH_FALSE: &'static [ConstInt] = &[ConstInt::U8(0)];
TerminatorKind::SwitchInt {
discr: cond,
switch_ty: tcx.types.bool,
/// Convert unique, zero-sized type for a fn to fn()
ReifyFnPointer,
+ /// Convert non capturing closure to fn()
+ ClosureFnPointer,
+
/// Convert safe fn() to unsafe fn()
UnsafeFnPointer,
substs: &'tcx Substs<'tcx>,
},
Value {
- value: ConstVal,
+ value: ConstVal<'tcx>,
},
Promoted {
// Index into the `promoted` vector of `Mir`.
write!(fmt, "b\"{}\"", escaped)
}
Bool(b) => write!(fmt, "{:?}", b),
- Function(def_id) => write!(fmt, "{}", item_path_str(def_id)),
+ Function(def_id, _) => write!(fmt, "{}", item_path_str(def_id)),
Struct(_) | Tuple(_) | Array(_) | Repeat(..) =>
bug!("ConstVal `{:?}` should not be in MIR", const_val),
Char(c) => write!(fmt, "{:?}", c),
Rvalue::Discriminant(ref lval) => {
let ty = lval.ty(mir, tcx).to_ty(tcx);
if let ty::TyAdt(adt_def, _) = ty.sty {
- Some(adt_def.discr_ty.to_ty(tcx))
+ Some(adt_def.repr.discr_type().to_ty(tcx))
} else {
// Undefined behaviour, bug for now; may want to return something for
// the `discriminant` intrinsic later.
tcx: TyCtxt<'a, 'tcx, 'tcx>,
hooks: &mut [Box<for<'s> MirPassHook<'s>>])
{
- let def_ids = tcx.mir_map.borrow().keys();
+ let def_ids = tcx.maps.mir.borrow().keys();
for def_id in def_ids {
if !def_id.is_local() {
continue;
}
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
- let mir = &mut tcx.mir_map.borrow()[&def_id].borrow_mut();
+ let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
tcx.dep_graph.write(DepNode::Mir(def_id));
let id = tcx.hir.as_local_node_id(def_id).unwrap();
pub uint_type: UintTy,
}
-#[derive(Clone)]
+#[derive(Clone, Hash)]
pub enum Sanitizer {
Address,
Leak,
// much sense: The search path can stay the same while the
// things discovered there might have changed on disk.
search_paths: SearchPaths [TRACKED],
- libs: Vec<(String, Option<String>, cstore::NativeLibraryKind)> [TRACKED],
+ libs: Vec<(String, Option<String>, Option<cstore::NativeLibraryKind>)> [TRACKED],
maybe_sysroot: Option<PathBuf> [TRACKED],
target_triple: String [TRACKED],
"save all temporary output files during compilation"),
rpath: bool = (false, parse_bool, [UNTRACKED],
"set rpath values in libs/exes"),
+ overflow_checks: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "use overflow checks for integer arithmetic"),
no_prepopulate_passes: bool = (false, parse_bool, [TRACKED],
"don't pre-populate the pass manager with a list of passes"),
no_vectorize_loops: bool = (false, parse_bool, [TRACKED],
"encode MIR of all functions into the crate metadata"),
osx_rpath_install_name: bool = (false, parse_bool, [TRACKED],
"pass `-install_name @rpath/...` to the OSX linker"),
- sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [UNTRACKED],
+ sanitizer: Option<Sanitizer> = (None, parse_sanitizer, [TRACKED],
"Use a sanitizer"),
}
let mut parts = s.splitn(2, '=');
let kind = parts.next().unwrap();
let (name, kind) = match (parts.next(), kind) {
- (None, name) |
- (Some(name), "dylib") => (name, cstore::NativeUnknown),
- (Some(name), "framework") => (name, cstore::NativeFramework),
- (Some(name), "static") => (name, cstore::NativeStatic),
- (Some(name), "static-nobundle") => (name, cstore::NativeStaticNobundle),
+ (None, name) => (name, None),
+ (Some(name), "dylib") => (name, Some(cstore::NativeUnknown)),
+ (Some(name), "framework") => (name, Some(cstore::NativeFramework)),
+ (Some(name), "static") => (name, Some(cstore::NativeStatic)),
+ (Some(name), "static-nobundle") => (name, Some(cstore::NativeStaticNobundle)),
(_, s) => {
early_error(error_format, &format!("unknown library kind `{}`, expected \
one of dylib, framework, or static",
s));
}
};
- if kind == cstore::NativeStaticNobundle && !nightly_options::is_nightly_build() {
+ if kind == Some(cstore::NativeStaticNobundle) && !nightly_options::is_nightly_build() {
early_error(error_format, &format!("the library kind 'static-nobundle' is only \
accepted on the nightly compiler"));
}
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
use super::{Passes, CrateType, OptLevel, DebugInfoLevel,
- OutputTypes, Externs, ErrorOutputType};
+ OutputTypes, Externs, ErrorOutputType, Sanitizer};
use syntax::feature_gate::UnstableFeatures;
use rustc_back::PanicStrategy;
impl_dep_tracking_hash_via_hash!(Option<PanicStrategy>);
impl_dep_tracking_hash_via_hash!(Option<lint::Level>);
impl_dep_tracking_hash_via_hash!(Option<PathBuf>);
+ impl_dep_tracking_hash_via_hash!(Option<cstore::NativeLibraryKind>);
impl_dep_tracking_hash_via_hash!(CrateType);
impl_dep_tracking_hash_via_hash!(PanicStrategy);
impl_dep_tracking_hash_via_hash!(Passes);
impl_dep_tracking_hash_via_hash!(Externs);
impl_dep_tracking_hash_via_hash!(OutputTypes);
impl_dep_tracking_hash_via_hash!(cstore::NativeLibraryKind);
+ impl_dep_tracking_hash_via_hash!(Sanitizer);
+ impl_dep_tracking_hash_via_hash!(Option<Sanitizer>);
impl_dep_tracking_hash_for_sortable_vec_of!(String);
impl_dep_tracking_hash_for_sortable_vec_of!(CrateType);
impl_dep_tracking_hash_for_sortable_vec_of!((String, lint::Level));
impl_dep_tracking_hash_for_sortable_vec_of!((String, Option<String>,
- cstore::NativeLibraryKind));
+ Option<cstore::NativeLibraryKind>));
impl DepTrackingHash for SearchPaths {
fn hash(&self, hasher: &mut DefaultHasher, _: ErrorOutputType) {
let mut elems: Vec<_> = self
let mut v4 = super::basic_options();
// Reference
- v1.libs = vec![(String::from("a"), None, cstore::NativeStatic),
- (String::from("b"), None, cstore::NativeFramework),
- (String::from("c"), None, cstore::NativeUnknown)];
+ v1.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+ (String::from("b"), None, Some(cstore::NativeFramework)),
+ (String::from("c"), None, Some(cstore::NativeUnknown))];
// Change label
- v2.libs = vec![(String::from("a"), None, cstore::NativeStatic),
- (String::from("X"), None, cstore::NativeFramework),
- (String::from("c"), None, cstore::NativeUnknown)];
+ v2.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+ (String::from("X"), None, Some(cstore::NativeFramework)),
+ (String::from("c"), None, Some(cstore::NativeUnknown))];
// Change kind
- v3.libs = vec![(String::from("a"), None, cstore::NativeStatic),
- (String::from("b"), None, cstore::NativeStatic),
- (String::from("c"), None, cstore::NativeUnknown)];
+ v3.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+ (String::from("b"), None, Some(cstore::NativeStatic)),
+ (String::from("c"), None, Some(cstore::NativeUnknown))];
// Change new-name
- v4.libs = vec![(String::from("a"), None, cstore::NativeStatic),
- (String::from("b"), Some(String::from("X")), cstore::NativeFramework),
- (String::from("c"), None, cstore::NativeUnknown)];
+ v4.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+ (String::from("b"), Some(String::from("X")), Some(cstore::NativeFramework)),
+ (String::from("c"), None, Some(cstore::NativeUnknown))];
assert!(v1.dep_tracking_hash() != v2.dep_tracking_hash());
assert!(v1.dep_tracking_hash() != v3.dep_tracking_hash());
let mut v3 = super::basic_options();
// Reference
- v1.libs = vec![(String::from("a"), None, cstore::NativeStatic),
- (String::from("b"), None, cstore::NativeFramework),
- (String::from("c"), None, cstore::NativeUnknown)];
+ v1.libs = vec![(String::from("a"), None, Some(cstore::NativeStatic)),
+ (String::from("b"), None, Some(cstore::NativeFramework)),
+ (String::from("c"), None, Some(cstore::NativeUnknown))];
- v2.libs = vec![(String::from("b"), None, cstore::NativeFramework),
- (String::from("a"), None, cstore::NativeStatic),
- (String::from("c"), None, cstore::NativeUnknown)];
+ v2.libs = vec![(String::from("b"), None, Some(cstore::NativeFramework)),
+ (String::from("a"), None, Some(cstore::NativeStatic)),
+ (String::from("c"), None, Some(cstore::NativeUnknown))];
- v3.libs = vec![(String::from("c"), None, cstore::NativeUnknown),
- (String::from("a"), None, cstore::NativeStatic),
- (String::from("b"), None, cstore::NativeFramework)];
+ v3.libs = vec![(String::from("c"), None, Some(cstore::NativeUnknown)),
+ (String::from("a"), None, Some(cstore::NativeStatic)),
+ (String::from("b"), None, Some(cstore::NativeFramework))];
assert!(v1.dep_tracking_hash() == v2.dep_tracking_hash());
assert!(v1.dep_tracking_hash() == v3.dep_tracking_hash());
opts.cg.llvm_args = vec![String::from("1"), String::from("2")];
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+ opts = reference.clone();
+ opts.cg.overflow_checks = Some(true);
+ assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
+
opts = reference.clone();
opts.cg.no_prepopulate_passes = true;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
pub target: config::Config,
pub host: Target,
pub opts: config::Options,
- pub cstore: Rc<for<'a> CrateStore<'a>>,
+ pub cstore: Rc<CrateStore>,
pub parse_sess: ParseSess,
// For a library crate, this is always none
pub entry_fn: RefCell<Option<(NodeId, Span)>>,
pub fn nonzeroing_move_hints(&self) -> bool {
self.opts.debugging_opts.enable_nonzeroing_move_hints
}
+ pub fn overflow_checks(&self) -> bool {
+ self.opts.cg.overflow_checks
+ .or(self.opts.debugging_opts.force_overflow_checks)
+ .unwrap_or(self.opts.debug_assertions)
+ }
pub fn must_not_eliminate_frame_pointers(&self) -> bool {
self.opts.debuginfo != DebugInfoLevel::NoDebugInfo ||
dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
registry: errors::registry::Registry,
- cstore: Rc<for<'a> CrateStore<'a>>)
+ cstore: Rc<CrateStore>)
-> Session {
build_session_with_codemap(sopts,
dep_graph,
dep_graph: &DepGraph,
local_crate_source_file: Option<PathBuf>,
registry: errors::registry::Registry,
- cstore: Rc<for<'a> CrateStore<'a>>,
+ cstore: Rc<CrateStore>,
codemap: Rc<codemap::CodeMap>,
emitter_dest: Option<Box<Write + Send>>)
-> Session {
local_crate_source_file: Option<PathBuf>,
span_diagnostic: errors::Handler,
codemap: Rc<codemap::CodeMap>,
- cstore: Rc<for<'a> CrateStore<'a>>)
+ cstore: Rc<CrateStore>)
-> Session {
let host = match Target::search(config::host_triple()) {
Ok(t) => t,
SelectionContext,
SelectionError,
ObjectSafetyViolation,
- MethodViolationCode,
};
use fmt_macros::{Parser, Piece, Position};
let span = obligation.cause.span;
let mut report = None;
- for item in self.tcx.get_attrs(def_id).iter() {
- if item.check_name("rustc_on_unimplemented") {
- let err_sp = item.meta().span.substitute_dummy(span);
- let trait_str = self.tcx.item_path_str(trait_ref.def_id);
- if let Some(istring) = item.value_str() {
- let istring = &*istring.as_str();
- let generics = self.tcx.item_generics(trait_ref.def_id);
- let generic_map = generics.types.iter().map(|param| {
- (param.name.as_str().to_string(),
- trait_ref.substs.type_for_def(param).to_string())
- }).collect::<FxHashMap<String, String>>();
- let parser = Parser::new(istring);
- let mut errored = false;
- let err: String = parser.filter_map(|p| {
- match p {
- Piece::String(s) => Some(s),
- Piece::NextArgument(a) => match a.position {
- Position::ArgumentNamed(s) => match generic_map.get(s) {
- Some(val) => Some(val),
- None => {
- span_err!(self.tcx.sess, err_sp, E0272,
- "the #[rustc_on_unimplemented] \
- attribute on \
- trait definition for {} refers to \
- non-existent type parameter {}",
- trait_str, s);
- errored = true;
- None
- }
- },
- _ => {
- span_err!(self.tcx.sess, err_sp, E0273,
- "the #[rustc_on_unimplemented] attribute \
- on trait definition for {} must have \
- named format arguments, eg \
- `#[rustc_on_unimplemented = \
- \"foo {{T}}\"]`", trait_str);
+ if let Some(item) = self.tcx
+ .get_attrs(def_id)
+ .into_iter()
+ .filter(|a| a.check_name("rustc_on_unimplemented"))
+ .next()
+ {
+ let err_sp = item.meta().span.substitute_dummy(span);
+ let trait_str = self.tcx.item_path_str(trait_ref.def_id);
+ if let Some(istring) = item.value_str() {
+ let istring = &*istring.as_str();
+ let generics = self.tcx.item_generics(trait_ref.def_id);
+ let generic_map = generics.types.iter().map(|param| {
+ (param.name.as_str().to_string(),
+ trait_ref.substs.type_for_def(param).to_string())
+ }).collect::<FxHashMap<String, String>>();
+ let parser = Parser::new(istring);
+ let mut errored = false;
+ let err: String = parser.filter_map(|p| {
+ match p {
+ Piece::String(s) => Some(s),
+ Piece::NextArgument(a) => match a.position {
+ Position::ArgumentNamed(s) => match generic_map.get(s) {
+ Some(val) => Some(val),
+ None => {
+ span_err!(self.tcx.sess, err_sp, E0272,
+ "the #[rustc_on_unimplemented] \
+ attribute on \
+ trait definition for {} refers to \
+ non-existent type parameter {}",
+ trait_str, s);
errored = true;
None
}
+ },
+ _ => {
+ span_err!(self.tcx.sess, err_sp, E0273,
+ "the #[rustc_on_unimplemented] attribute \
+ on trait definition for {} must have \
+ named format arguments, eg \
+ `#[rustc_on_unimplemented = \
+ \"foo {{T}}\"]`", trait_str);
+ errored = true;
+ None
}
}
- }).collect();
- // Report only if the format string checks out
- if !errored {
- report = Some(err);
}
- } else {
- span_err!(self.tcx.sess, err_sp, E0274,
- "the #[rustc_on_unimplemented] attribute on \
- trait definition for {} must have a value, \
- eg `#[rustc_on_unimplemented = \"foo\"]`",
- trait_str);
+ }).collect();
+ // Report only if the format string checks out
+ if !errored {
+ report = Some(err);
}
- break;
+ } else {
+ span_err!(self.tcx.sess, err_sp, E0274,
+ "the #[rustc_on_unimplemented] attribute on \
+ trait definition for {} must have a value, \
+ eg `#[rustc_on_unimplemented = \"foo\"]`",
+ trait_str);
}
}
report
}
fn report_similar_impl_candidates(&self,
- trait_ref: ty::PolyTraitRef<'tcx>,
+ impl_candidates: Vec<ty::TraitRef<'tcx>>,
err: &mut DiagnosticBuilder)
{
- let simp = fast_reject::simplify_type(self.tcx,
- trait_ref.skip_binder().self_ty(),
- true);
- let mut impl_candidates = Vec::new();
- let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id());
-
- match simp {
- Some(simp) => trait_def.for_each_impl(self.tcx, |def_id| {
- let imp = self.tcx.impl_trait_ref(def_id).unwrap();
- let imp_simp = fast_reject::simplify_type(self.tcx,
- imp.self_ty(),
- true);
- if let Some(imp_simp) = imp_simp {
- if simp != imp_simp {
- return;
- }
- }
- impl_candidates.push(imp);
- }),
- None => trait_def.for_each_impl(self.tcx, |def_id| {
- impl_candidates.push(
- self.tcx.impl_trait_ref(def_id).unwrap());
- })
- };
-
if impl_candidates.is_empty() {
return;
}
lint_id)
.emit();
return;
- } else {
- match obligation.predicate {
- ty::Predicate::Trait(ref trait_predicate) => {
- let trait_predicate =
- self.resolve_type_vars_if_possible(trait_predicate);
-
- if self.tcx.sess.has_errors() && trait_predicate.references_error() {
- return;
- } else {
- let trait_ref = trait_predicate.to_poly_trait_ref();
- let (post_message, pre_message) = match self.get_parent_trait_ref(
- &obligation.cause.code)
- {
- Some(t) => {
- (format!(" in `{}`", t), format!("within `{}`, ", t))
- }
- None => (String::new(), String::new()),
- };
- let mut err = struct_span_err!(
- self.tcx.sess,
- span,
- E0277,
- "the trait bound `{}` is not satisfied{}",
- trait_ref.to_predicate(),
- post_message);
- err.span_label(span,
- &format!("{}the trait `{}` is not \
- implemented for `{}`",
- pre_message,
- trait_ref,
- trait_ref.self_ty()));
-
- // Try to report a help message
-
- if !trait_ref.has_infer_types() &&
- self.predicate_can_apply(trait_ref) {
- // If a where-clause may be useful, remind the
- // user that they can add it.
- //
- // don't display an on-unimplemented note, as
- // these notes will often be of the form
- // "the type `T` can't be frobnicated"
- // which is somewhat confusing.
- err.help(&format!("consider adding a `where {}` bound",
- trait_ref.to_predicate()));
- } else if let Some(s) = self.on_unimplemented_note(trait_ref,
- obligation) {
- // If it has a custom "#[rustc_on_unimplemented]"
- // error message, let's display it!
- err.note(&s);
- } else {
- // If we can't show anything useful, try to find
- // similar impls.
- let impl_candidates =
- self.find_similar_impl_candidates(trait_ref);
- if impl_candidates.len() > 0 {
- self.report_similar_impl_candidates(trait_ref, &mut err);
- }
- }
- err
- }
- }
+ }
+ match obligation.predicate {
+ ty::Predicate::Trait(ref trait_predicate) => {
+ let trait_predicate =
+ self.resolve_type_vars_if_possible(trait_predicate);
- ty::Predicate::Equate(ref predicate) => {
- let predicate = self.resolve_type_vars_if_possible(predicate);
- let err = self.equality_predicate(&obligation.cause,
- &predicate).err().unwrap();
- struct_span_err!(self.tcx.sess, span, E0278,
- "the requirement `{}` is not satisfied (`{}`)",
- predicate, err)
+ if self.tcx.sess.has_errors() && trait_predicate.references_error() {
+ return;
}
-
- ty::Predicate::RegionOutlives(ref predicate) => {
- let predicate = self.resolve_type_vars_if_possible(predicate);
- let err = self.region_outlives_predicate(&obligation.cause,
- &predicate).err().unwrap();
- struct_span_err!(self.tcx.sess, span, E0279,
- "the requirement `{}` is not satisfied (`{}`)",
- predicate, err)
+ let trait_ref = trait_predicate.to_poly_trait_ref();
+ let (post_message, pre_message) =
+ self.get_parent_trait_ref(&obligation.cause.code)
+ .map(|t| (format!(" in `{}`", t), format!("within `{}`, ", t)))
+ .unwrap_or((String::new(), String::new()));
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ span,
+ E0277,
+ "the trait bound `{}` is not satisfied{}",
+ trait_ref.to_predicate(),
+ post_message);
+ err.span_label(span,
+ &format!("{}the trait `{}` is not \
+ implemented for `{}`",
+ pre_message,
+ trait_ref,
+ trait_ref.self_ty()));
+
+ // Try to report a help message
+
+ if !trait_ref.has_infer_types() &&
+ self.predicate_can_apply(trait_ref) {
+ // If a where-clause may be useful, remind the
+ // user that they can add it.
+ //
+ // don't display an on-unimplemented note, as
+ // these notes will often be of the form
+ // "the type `T` can't be frobnicated"
+ // which is somewhat confusing.
+ err.help(&format!("consider adding a `where {}` bound",
+ trait_ref.to_predicate()));
+ } else if let Some(s) = self.on_unimplemented_note(trait_ref,
+ obligation) {
+ // If it has a custom "#[rustc_on_unimplemented]"
+ // error message, let's display it!
+ err.note(&s);
+ } else {
+ // If we can't show anything useful, try to find
+ // similar impls.
+ let impl_candidates = self.find_similar_impl_candidates(trait_ref);
+ self.report_similar_impl_candidates(impl_candidates, &mut err);
}
+ err
+ }
- ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
- let predicate =
- self.resolve_type_vars_if_possible(&obligation.predicate);
- struct_span_err!(self.tcx.sess, span, E0280,
- "the requirement `{}` is not satisfied",
- predicate)
- }
+ ty::Predicate::Equate(ref predicate) => {
+ let predicate = self.resolve_type_vars_if_possible(predicate);
+ let err = self.equality_predicate(&obligation.cause,
+ &predicate).err().unwrap();
+ struct_span_err!(self.tcx.sess, span, E0278,
+ "the requirement `{}` is not satisfied (`{}`)",
+ predicate, err)
+ }
- ty::Predicate::ObjectSafe(trait_def_id) => {
- let violations = self.tcx.object_safety_violations(trait_def_id);
- self.tcx.report_object_safety_error(span,
- trait_def_id,
- violations)
- }
+ ty::Predicate::RegionOutlives(ref predicate) => {
+ let predicate = self.resolve_type_vars_if_possible(predicate);
+ let err = self.region_outlives_predicate(&obligation.cause,
+ &predicate).err().unwrap();
+ struct_span_err!(self.tcx.sess, span, E0279,
+ "the requirement `{}` is not satisfied (`{}`)",
+ predicate, err)
+ }
- ty::Predicate::ClosureKind(closure_def_id, kind) => {
- let found_kind = self.closure_kind(closure_def_id).unwrap();
- let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
- let mut err = struct_span_err!(
- self.tcx.sess, closure_span, E0525,
- "expected a closure that implements the `{}` trait, \
- but this closure only implements `{}`",
- kind,
- found_kind);
- err.span_note(
- obligation.cause.span,
- &format!("the requirement to implement \
- `{}` derives from here", kind));
- err.emit();
- return;
- }
+ ty::Predicate::Projection(..) | ty::Predicate::TypeOutlives(..) => {
+ let predicate =
+ self.resolve_type_vars_if_possible(&obligation.predicate);
+ struct_span_err!(self.tcx.sess, span, E0280,
+ "the requirement `{}` is not satisfied",
+ predicate)
+ }
- ty::Predicate::WellFormed(ty) => {
- // WF predicates cannot themselves make
- // errors. They can only block due to
- // ambiguity; otherwise, they always
- // degenerate into other obligations
- // (which may fail).
- span_bug!(span, "WF predicate not satisfied for {:?}", ty);
- }
+ ty::Predicate::ObjectSafe(trait_def_id) => {
+ let violations = self.tcx.object_safety_violations(trait_def_id);
+ self.tcx.report_object_safety_error(span,
+ trait_def_id,
+ violations)
+ }
+
+ ty::Predicate::ClosureKind(closure_def_id, kind) => {
+ let found_kind = self.closure_kind(closure_def_id).unwrap();
+ let closure_span = self.tcx.hir.span_if_local(closure_def_id).unwrap();
+ let mut err = struct_span_err!(
+ self.tcx.sess, closure_span, E0525,
+ "expected a closure that implements the `{}` trait, \
+ but this closure only implements `{}`",
+ kind,
+ found_kind);
+ err.span_note(
+ obligation.cause.span,
+ &format!("the requirement to implement \
+ `{}` derives from here", kind));
+ err.emit();
+ return;
+ }
+
+ ty::Predicate::WellFormed(ty) => {
+ // WF predicates cannot themselves make
+ // errors. They can only block due to
+ // ambiguity; otherwise, they always
+ // degenerate into other obligations
+ // (which may fail).
+ span_bug!(span, "WF predicate not satisfied for {:?}", ty);
}
}
}
if !reported_violations.insert(violation.clone()) {
continue;
}
- let buf;
- let note = match violation {
- ObjectSafetyViolation::SizedSelf => {
- "the trait cannot require that `Self : Sized`"
- }
-
- ObjectSafetyViolation::SupertraitSelf => {
- "the trait cannot use `Self` as a type parameter \
- in the supertrait listing"
- }
-
- ObjectSafetyViolation::Method(name,
- MethodViolationCode::StaticMethod) => {
- buf = format!("method `{}` has no receiver", name);
- &buf
- }
-
- ObjectSafetyViolation::Method(name,
- MethodViolationCode::ReferencesSelf) => {
- buf = format!("method `{}` references the `Self` type \
- in its arguments or return type",
- name);
- &buf
- }
-
- ObjectSafetyViolation::Method(name,
- MethodViolationCode::Generic) => {
- buf = format!("method `{}` has generic type parameters", name);
- &buf
- }
- };
- err.note(note);
+ err.note(&violation.error_msg());
}
err
}
let trait_ref = data.to_poly_trait_ref();
let self_ty = trait_ref.self_ty();
if predicate.references_error() {
- } else {
- // Typically, this ambiguity should only happen if
- // there are unresolved type inference variables
- // (otherwise it would suggest a coherence
- // failure). But given #21974 that is not necessarily
- // the case -- we can have multiple where clauses that
- // are only distinguished by a region, which results
- // in an ambiguity even when all types are fully
- // known, since we don't dispatch based on region
- // relationships.
-
- // This is kind of a hack: it frequently happens that some earlier
- // error prevents types from being fully inferred, and then we get
- // a bunch of uninteresting errors saying something like "<generic
- // #0> doesn't implement Sized". It may even be true that we
- // could just skip over all checks where the self-ty is an
- // inference variable, but I was afraid that there might be an
- // inference variable created, registered as an obligation, and
- // then never forced by writeback, and hence by skipping here we'd
- // be ignoring the fact that we don't KNOW the type works
- // out. Though even that would probably be harmless, given that
- // we're only talking about builtin traits, which are known to be
- // inhabited. But in any case I just threw in this check for
- // has_errors() to be sure that compilation isn't happening
- // anyway. In that case, why inundate the user.
- if !self.tcx.sess.has_errors() {
- if
- self.tcx.lang_items.sized_trait()
- .map_or(false, |sized_id| sized_id == trait_ref.def_id())
- {
- self.need_type_info(obligation, self_ty);
- } else {
- let mut err = struct_span_err!(self.tcx.sess,
- obligation.cause.span, E0283,
- "type annotations required: \
- cannot resolve `{}`",
- predicate);
- self.note_obligation_cause(&mut err, obligation);
- err.emit();
- }
+ return;
+ }
+ // Typically, this ambiguity should only happen if
+ // there are unresolved type inference variables
+ // (otherwise it would suggest a coherence
+ // failure). But given #21974 that is not necessarily
+ // the case -- we can have multiple where clauses that
+ // are only distinguished by a region, which results
+ // in an ambiguity even when all types are fully
+ // known, since we don't dispatch based on region
+ // relationships.
+
+ // This is kind of a hack: it frequently happens that some earlier
+ // error prevents types from being fully inferred, and then we get
+ // a bunch of uninteresting errors saying something like "<generic
+ // #0> doesn't implement Sized". It may even be true that we
+ // could just skip over all checks where the self-ty is an
+ // inference variable, but I was afraid that there might be an
+ // inference variable created, registered as an obligation, and
+ // then never forced by writeback, and hence by skipping here we'd
+ // be ignoring the fact that we don't KNOW the type works
+ // out. Though even that would probably be harmless, given that
+ // we're only talking about builtin traits, which are known to be
+ // inhabited. But in any case I just threw in this check for
+ // has_errors() to be sure that compilation isn't happening
+ // anyway. In that case, why inundate the user.
+ if !self.tcx.sess.has_errors() {
+ if
+ self.tcx.lang_items.sized_trait()
+ .map_or(false, |sized_id| sized_id == trait_ref.def_id())
+ {
+ self.need_type_info(obligation, self_ty);
+ } else {
+ let mut err = struct_span_err!(self.tcx.sess,
+ obligation.cause.span, E0283,
+ "type annotations required: \
+ cannot resolve `{}`",
+ predicate);
+ self.note_obligation_cause(&mut err, obligation);
+ err.emit();
}
}
}
use dep_graph::DepGraph;
use infer::{InferCtxt, InferOk};
use ty::{self, Ty, TypeFoldable, ToPolyTraitRef, TyCtxt, ToPredicate};
-use ty::subst::Subst;
use rustc_data_structures::obligation_forest::{ObligationForest, Error};
use rustc_data_structures::obligation_forest::{ForestObligation, ObligationProcessor};
use std::marker::PhantomData;
-use std::mem;
use syntax::ast;
use util::nodemap::{FxHashSet, NodeMap};
use hir::def_id::DefId;
use super::CodeAmbiguity;
use super::CodeProjectionError;
use super::CodeSelectionError;
-use super::{FulfillmentError, FulfillmentErrorCode, SelectionError};
-use super::{ObligationCause, BuiltinDerivedObligation};
-use super::{PredicateObligation, TraitObligation, Obligation};
+use super::{FulfillmentError, FulfillmentErrorCode};
+use super::{ObligationCause, PredicateObligation, Obligation};
use super::project;
use super::select::SelectionContext;
use super::Unimplemented;
// obligations (otherwise, it's easy to fail to walk to a
// particular node-id).
region_obligations: NodeMap<Vec<RegionObligation<'tcx>>>,
-
- // A list of obligations that need to be deferred to
- // a later time for them to be properly fulfilled.
- deferred_obligations: Vec<DeferredObligation<'tcx>>,
}
#[derive(Clone)]
pub stalled_on: Vec<Ty<'tcx>>,
}
-/// An obligation which cannot be fulfilled in the context
-/// it was registered in, such as auto trait obligations on
-/// `impl Trait`, which require the concrete type to be
-/// available, only guaranteed after finishing type-checking.
-#[derive(Clone, Debug)]
-pub struct DeferredObligation<'tcx> {
- pub predicate: ty::PolyTraitPredicate<'tcx>,
- pub cause: ObligationCause<'tcx>
-}
-
-impl<'a, 'gcx, 'tcx> DeferredObligation<'tcx> {
- /// If possible, create a `DeferredObligation` from
- /// a trait predicate which had failed selection,
- /// but could succeed later.
- pub fn from_select_error(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- obligation: &TraitObligation<'tcx>,
- selection_err: &SelectionError<'tcx>)
- -> Option<DeferredObligation<'tcx>> {
- if let Unimplemented = *selection_err {
- if DeferredObligation::must_defer(tcx, &obligation.predicate) {
- return Some(DeferredObligation {
- predicate: obligation.predicate.clone(),
- cause: obligation.cause.clone()
- });
- }
- }
-
- None
- }
-
- /// Returns true if the given trait predicate can be
- /// fulfilled at a later time.
- pub fn must_defer(tcx: TyCtxt<'a, 'gcx, 'tcx>,
- predicate: &ty::PolyTraitPredicate<'tcx>)
- -> bool {
- // Auto trait obligations on `impl Trait`.
- if tcx.trait_has_default_impl(predicate.def_id()) {
- let substs = predicate.skip_binder().trait_ref.substs;
- if substs.types().count() == 1 && substs.regions().next().is_none() {
- if let ty::TyAnon(..) = predicate.skip_binder().self_ty().sty {
- return true;
- }
- }
- }
-
- false
- }
-
- /// If possible, return the nested obligations required
- /// to fulfill this obligation.
- pub fn try_select(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
- -> Option<Vec<PredicateObligation<'tcx>>> {
- if let ty::TyAnon(def_id, substs) = self.predicate.skip_binder().self_ty().sty {
- let ty = if def_id.is_local() {
- tcx.item_types.borrow().get(&def_id).cloned()
- } else {
- Some(tcx.item_type(def_id))
- };
- // We can resolve the `impl Trait` to its concrete type.
- if let Some(concrete_ty) = ty.subst(tcx, substs) {
- let predicate = ty::TraitRef {
- def_id: self.predicate.def_id(),
- substs: tcx.mk_substs_trait(concrete_ty, &[])
- }.to_predicate();
-
- let original_obligation = Obligation::new(self.cause.clone(),
- self.predicate.clone());
- let cause = original_obligation.derived_cause(BuiltinDerivedObligation);
- return Some(vec![Obligation::new(cause, predicate)]);
- }
- }
-
- None
- }
-
- /// Return the `PredicateObligation` this was created from.
- pub fn to_obligation(&self) -> PredicateObligation<'tcx> {
- let predicate = ty::Predicate::Trait(self.predicate.clone());
- Obligation::new(self.cause.clone(), predicate)
- }
-
- /// Return an error as if this obligation had failed.
- pub fn to_error(&self) -> FulfillmentError<'tcx> {
- FulfillmentError::new(self.to_obligation(), CodeSelectionError(Unimplemented))
- }
-}
-
impl<'a, 'gcx, 'tcx> FulfillmentContext<'tcx> {
/// Creates a new fulfillment context.
pub fn new() -> FulfillmentContext<'tcx> {
FulfillmentContext {
predicates: ObligationForest::new(),
region_obligations: NodeMap(),
- deferred_obligations: vec![],
}
}
{
self.select_where_possible(infcx)?;
- // Fail all of the deferred obligations that haven't
- // been otherwise removed from the context.
- let deferred_errors = self.deferred_obligations.iter()
- .map(|d| d.to_error());
-
let errors: Vec<_> =
self.predicates.to_errors(CodeAmbiguity)
.into_iter()
.map(|e| to_fulfillment_error(e))
- .chain(deferred_errors)
.collect();
if errors.is_empty() {
Ok(())
self.predicates.pending_obligations()
}
- pub fn take_deferred_obligations(&mut self) -> Vec<DeferredObligation<'tcx>> {
- mem::replace(&mut self.deferred_obligations, vec![])
- }
-
/// Attempts to select obligations using `selcx`. If `only_new_obligations` is true, then it
/// only attempts to select obligations that haven't been seen before.
fn select(&mut self, selcx: &mut SelectionContext<'a, 'gcx, 'tcx>)
let outcome = self.predicates.process_obligations(&mut FulfillProcessor {
selcx: selcx,
region_obligations: &mut self.region_obligations,
- deferred_obligations: &mut self.deferred_obligations
});
debug!("select: outcome={:?}", outcome);
struct FulfillProcessor<'a, 'b: 'a, 'gcx: 'tcx, 'tcx: 'b> {
selcx: &'a mut SelectionContext<'b, 'gcx, 'tcx>,
region_obligations: &'a mut NodeMap<Vec<RegionObligation<'tcx>>>,
- deferred_obligations: &'a mut Vec<DeferredObligation<'tcx>>
}
impl<'a, 'b, 'gcx, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'gcx, 'tcx> {
{
process_predicate(self.selcx,
obligation,
- self.region_obligations,
- self.deferred_obligations)
+ self.region_obligations)
.map(|os| os.map(|os| os.into_iter().map(|o| PendingPredicateObligation {
obligation: o,
stalled_on: vec![]
fn process_predicate<'a, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'a, 'gcx, 'tcx>,
pending_obligation: &mut PendingPredicateObligation<'tcx>,
- region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
- deferred_obligations: &mut Vec<DeferredObligation<'tcx>>)
+ region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
-> Result<Option<Vec<PredicateObligation<'tcx>>>,
FulfillmentErrorCode<'tcx>>
{
info!("selecting trait `{:?}` at depth {} yielded Err",
data, obligation.recursion_depth);
- let defer = DeferredObligation::from_select_error(selcx.tcx(),
- &trait_obligation,
- &selection_err);
- if let Some(deferred_obligation) = defer {
- if let Some(nested) = deferred_obligation.try_select(selcx.tcx()) {
- Ok(Some(nested))
- } else {
- // Pretend that the obligation succeeded,
- // but record it for later.
- deferred_obligations.push(deferred_obligation);
- Ok(Some(vec![]))
- }
- } else {
- Err(CodeSelectionError(selection_err))
- }
+ Err(CodeSelectionError(selection_err))
}
}
}
// already has the required read edges, so we don't need
// to add any more edges here.
if data.is_global() {
- // Don't cache predicates which were fulfilled
- // by deferring them for later fulfillment.
- if DeferredObligation::must_defer(tcx, data) {
- return;
- }
-
if let Some(data) = tcx.lift_to_global(data) {
if self.set.insert(data.clone()) {
debug!("add_if_global: global predicate `{:?}` added", data);
pub use self::coherence::overlapping_impls;
pub use self::coherence::OrphanCheckErr;
pub use self::fulfill::{FulfillmentContext, GlobalFulfilledPredicates, RegionObligation};
-pub use self::fulfill::DeferredObligation;
pub use self::project::MismatchedProjectionTypes;
pub use self::project::{normalize, normalize_projection_type, Normalized};
pub use self::project::{ProjectionCache, ProjectionCacheSnapshot, Reveal};
let elaborated_env = unnormalized_env.with_caller_bounds(predicates);
- tcx.infer_ctxt(elaborated_env, Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt(elaborated_env, Reveal::UserFacing).enter(|infcx| {
let predicates = match fully_normalize(&infcx, cause,
&infcx.parameter_environment.caller_bounds) {
Ok(predicates) => predicates,
use traits;
use ty::{self, Ty, TyCtxt, TypeFoldable};
use ty::subst::Substs;
+use std::borrow::Cow;
use syntax::ast;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
Method(ast::Name, MethodViolationCode),
}
+impl ObjectSafetyViolation {
+ pub fn error_msg(&self) -> Cow<'static, str> {
+ match *self {
+ ObjectSafetyViolation::SizedSelf =>
+ "the trait cannot require that `Self : Sized`".into(),
+ ObjectSafetyViolation::SupertraitSelf =>
+ "the trait cannot use `Self` as a type parameter \
+ in the supertrait listing".into(),
+ ObjectSafetyViolation::Method(name, MethodViolationCode::StaticMethod) =>
+ format!("method `{}` has no receiver", name).into(),
+ ObjectSafetyViolation::Method(name, MethodViolationCode::ReferencesSelf) =>
+ format!("method `{}` references the `Self` type \
+ in its arguments or return type", name).into(),
+ ObjectSafetyViolation::Method(name, MethodViolationCode::Generic) =>
+ format!("method `{}` has generic type parameters", name).into(),
+ }
+ }
+}
+
/// Reasons a method might not be object-safe.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum MethodViolationCode {
/// more or less conservative.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Reveal {
- /// FIXME (#32205)
- /// At coherence-checking time, we're still constructing the
- /// specialization graph, and thus we only project
- /// non-`default` associated types that are defined directly in
- /// the applicable impl. (This behavior should be improved over
- /// time, to allow for successful projections modulo cycles
- /// between different impls).
- ///
- /// Here's an example that will fail due to the restriction:
- ///
- /// ```
- /// trait Assoc {
- /// type Output;
- /// }
- ///
- /// impl<T> Assoc for T {
- /// type Output = bool;
- /// }
- ///
- /// impl Assoc for u8 {} // <- inherits the non-default type from above
- ///
- /// trait Foo {}
- /// impl Foo for u32 {}
- /// impl Foo for <u8 as Assoc>::Output {} // <- this projection will fail
- /// ```
- ///
- /// The projection would succeed if `Output` had been defined
- /// directly in the impl for `u8`.
- ExactMatch,
-
/// At type-checking time, we refuse to project any associated
/// type that is marked `default`. Non-`default` ("final") types
/// are always projected. This is necessary in general for
/// fn main() {
/// let <() as Assoc>::Output = true;
/// }
- NotSpecializable,
+ UserFacing,
/// At trans time, all monomorphic projections will succeed.
/// Also, `impl Trait` is normalized to the concrete type,
-> Progress<'tcx>
{
let closure_typer = selcx.closure_typer();
- let closure_type = closure_typer.closure_type(vtable.closure_def_id, vtable.substs);
+ let closure_type = closure_typer.closure_type(vtable.closure_def_id)
+ .subst(selcx.tcx(), vtable.substs.substs);
let Normalized {
value: closure_type,
obligations
confirm_callable_candidate(selcx,
obligation,
- &closure_type.sig,
+ closure_type,
util::TupleArgumentsFlag::No)
.with_addl_obligations(vtable.nested)
.with_addl_obligations(obligations)
fn confirm_callable_candidate<'cx, 'gcx, 'tcx>(
selcx: &mut SelectionContext<'cx, 'gcx, 'tcx>,
obligation: &ProjectionTyObligation<'tcx>,
- fn_sig: &ty::PolyFnSig<'tcx>,
+ fn_sig: ty::PolyFnSig<'tcx>,
flag: util::TupleArgumentsFlag)
-> Progress<'tcx>
{
-> Option<specialization_graph::NodeItem<ty::AssociatedItem>>
{
let trait_def_id = selcx.tcx().impl_trait_ref(impl_def_id).unwrap().def_id;
+ let trait_def = selcx.tcx().lookup_trait_def(trait_def_id);
- if selcx.projection_mode() == Reveal::ExactMatch {
+ if !trait_def.is_complete(selcx.tcx()) {
let impl_node = specialization_graph::Node::Impl(impl_def_id);
for item in impl_node.items(selcx.tcx()) {
if item.kind == ty::AssociatedKind::Type && item.name == assoc_ty_name {
}
None
} else {
- selcx.tcx().lookup_trait_def(trait_def_id)
+ trait_def
.ancestors(impl_def_id)
.defs(selcx.tcx(), assoc_ty_name, ty::AssociatedKind::Type)
.next()
}
// provide an impl, but only for suitable `fn` pointers
- ty::TyFnDef(.., &ty::BareFnTy {
+ ty::TyFnDef(.., ty::Binder(ty::FnSig {
unsafety: hir::Unsafety::Normal,
abi: Abi::Rust,
- ref sig,
- }) |
- ty::TyFnPtr(&ty::BareFnTy {
+ variadic: false,
+ ..
+ })) |
+ ty::TyFnPtr(ty::Binder(ty::FnSig {
unsafety: hir::Unsafety::Normal,
abi: Abi::Rust,
- ref sig
- }) if !sig.variadic() => {
+ variadic: false,
+ ..
+ })) => {
candidates.vec.push(FnPointerCandidate);
}
// `assemble_candidates_from_object_ty`.
}
ty::TyParam(..) |
- ty::TyProjection(..) |
- ty::TyAnon(..) => {
+ ty::TyProjection(..) => {
// In these cases, we don't know what the actual
// type is. Therefore, we cannot break it down
// into its constituent types. So we don't
ty::TyDynamic(..) |
ty::TyParam(..) |
ty::TyProjection(..) |
- ty::TyAnon(..) |
ty::TyInfer(ty::TyVar(_)) |
ty::TyInfer(ty::FreshTy(_)) |
ty::TyInfer(ty::FreshIntTy(_)) |
.map(|f| f.ty(self.tcx(), substs))
.collect()
}
+
+ ty::TyAnon(def_id, substs) => {
+ // We can resolve the `impl Trait` to its concrete type,
+ // which enforces a DAG between the functions requiring
+ // the auto trait bounds in question.
+ vec![self.tcx().item_type(def_id).subst(self.tcx(), substs)]
+ }
}
}
substs: ty::ClosureSubsts<'tcx>)
-> ty::PolyTraitRef<'tcx>
{
- let closure_type = self.infcx.closure_type(closure_def_id, substs);
+ let closure_type = self.infcx.closure_type(closure_def_id)
+ .subst(self.tcx(), substs.substs);
let ty::Binder((trait_ref, _)) =
self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(),
obligation.predicate.0.self_ty(), // (1)
- &closure_type.sig,
+ closure_type,
util::TupleArgumentsFlag::No);
// (1) Feels icky to skip the binder here, but OTOH we know
// that the self-type is an unboxed closure type and hence is
.subst(tcx, &penv.free_substs);
// Create a infcx, taking the predicates of impl1 as assumptions:
- let result = tcx.infer_ctxt(penv, Reveal::ExactMatch).enter(|infcx| {
+ let result = tcx.infer_ctxt(penv, Reveal::UserFacing).enter(|infcx| {
// Normalize the trait reference. The WF rules ought to ensure
// that this always succeeds.
let impl1_trait_ref =
let possible_sibling = *slot;
let tcx = tcx.global_tcx();
- let (le, ge) = tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
+ let (le, ge) = tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
let overlap = traits::overlapping_impls(&infcx,
possible_sibling,
impl_def_id);
}
}
-impl<'a, 'tcx> Lift<'tcx> for traits::DeferredObligation<'a> {
- type Lifted = traits::DeferredObligation<'tcx>;
- fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
- tcx.lift(&self.predicate).and_then(|predicate| {
- tcx.lift(&self.cause).map(|cause| {
- traits::DeferredObligation {
- predicate: predicate,
- cause: cause
- }
- })
- })
- }
-}
-
// For trans only.
impl<'a, 'tcx> Lift<'tcx> for traits::Vtable<'a, ()> {
type Lifted = traits::Vtable<'tcx, ()>;
self.code.visit_with(visitor)
}
}
-
-impl<'tcx> TypeFoldable<'tcx> for traits::DeferredObligation<'tcx> {
- fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- traits::DeferredObligation {
- predicate: self.predicate.fold_with(folder),
- cause: self.cause.fold_with(folder)
- }
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.predicate.visit_with(visitor) || self.cause.visit_with(visitor)
- }
-}
pub fn closure_trait_ref_and_return_type(self,
fn_trait_def_id: DefId,
self_ty: Ty<'tcx>,
- sig: &ty::PolyFnSig<'tcx>,
+ sig: ty::PolyFnSig<'tcx>,
tuple_arguments: TupleArgumentsFlag)
-> ty::Binder<(ty::TraitRef<'tcx>, Ty<'tcx>)>
{
/// Go from a safe fn pointer to an unsafe fn pointer.
UnsafeFnPointer,
+ // Go from a non-capturing closure to an fn pointer.
+ ClosureFnPointer,
+
/// Go from a mut raw pointer to a const raw pointer.
MutToConstPointer,
Adjust::ReifyFnPointer |
Adjust::UnsafeFnPointer |
+ Adjust::ClosureFnPointer |
Adjust::MutToConstPointer |
Adjust::DerefRef {..} => false,
}
res = res - TC::OwnsDtor;
}
- if def.has_dtor() {
+ if def.has_dtor(tcx) {
res = res | TC::OwnsDtor;
}
//! type context book-keeping
-use dep_graph::{DepGraph, DepTrackingMap};
+use dep_graph::DepGraph;
use session::Session;
use lint;
use middle;
use ty::{TyS, TypeVariants, Slice};
use ty::{AdtKind, AdtDef, ClosureSubsts, Region};
use hir::FreevarMap;
-use ty::{BareFnTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
+use ty::{PolyFnSig, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
use ty::{TyVar, TyVid, IntVar, IntVid, FloatVar, FloatVid};
use ty::TypeVariants::*;
use ty::layout::{Layout, TargetDataLayout};
use ty::inhabitedness::DefIdForest;
use ty::maps;
-use util::common::MemoizationMap;
use util::nodemap::{NodeMap, NodeSet, DefIdMap, DefIdSet};
use util::nodemap::{FxHashMap, FxHashSet};
use rustc_data_structures::accumulate_vec::AccumulateVec;
use arena::{TypedArena, DroplessArena};
+use rustc_data_structures::indexed_vec::IndexVec;
use std::borrow::Borrow;
use std::cell::{Cell, RefCell};
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
-use std::rc::Rc;
use std::iter;
use std::cmp::Ordering;
+use syntax::abi;
use syntax::ast::{self, Name, NodeId};
use syntax::attr;
use syntax::symbol::{Symbol, keywords};
layout: TypedArena<Layout>,
// references
- generics: TypedArena<ty::Generics<'tcx>>,
+ generics: TypedArena<ty::Generics>,
trait_def: TypedArena<ty::TraitDef>,
adt_def: TypedArena<ty::AdtDef>,
mir: TypedArena<RefCell<Mir<'tcx>>>,
type_: RefCell<FxHashSet<Interned<'tcx, TyS<'tcx>>>>,
type_list: RefCell<FxHashSet<Interned<'tcx, Slice<Ty<'tcx>>>>>,
substs: RefCell<FxHashSet<Interned<'tcx, Substs<'tcx>>>>,
- bare_fn: RefCell<FxHashSet<Interned<'tcx, BareFnTy<'tcx>>>>,
region: RefCell<FxHashSet<Interned<'tcx, Region>>>,
existential_predicates: RefCell<FxHashSet<Interned<'tcx, Slice<ExistentialPredicate<'tcx>>>>>,
}
type_: RefCell::new(FxHashSet()),
type_list: RefCell::new(FxHashSet()),
substs: RefCell::new(FxHashSet()),
- bare_fn: RefCell::new(FxHashSet()),
region: RefCell::new(FxHashSet()),
existential_predicates: RefCell::new(FxHashSet()),
}
pub upvar_capture_map: ty::UpvarCaptureMap<'tcx>,
/// Records the type of each closure.
- pub closure_tys: NodeMap<ty::ClosureTy<'tcx>>,
+ pub closure_tys: NodeMap<ty::PolyFnSig<'tcx>>,
- /// Records the type of each closure.
+ /// Records the kind of each closure.
pub closure_kinds: NodeMap<ty::ClosureKind>,
/// For each fn, records the "liberated" types of its arguments
/// Lints for the body of this fn generated by typeck.
pub lints: lint::LintTable,
+
+ /// Set of trait imports actually used in the method resolution.
+ /// This is used for warning unused imports.
+ pub used_trait_imports: DefIdSet,
+
+ /// If any errors occurred while type-checking this body,
+ /// this field will be set to `true`.
+ pub tainted_by_errors: bool,
}
impl<'tcx> TypeckTables<'tcx> {
fru_field_types: NodeMap(),
cast_kinds: NodeMap(),
lints: lint::LintTable::new(),
+ used_trait_imports: DefIdSet(),
+ tainted_by_errors: false,
}
}
global_arenas: &'tcx GlobalArenas<'tcx>,
global_interners: CtxtInterners<'tcx>,
+ pub sess: &'tcx Session,
+
pub specializes_cache: RefCell<traits::SpecializesCache>,
pub dep_graph: DepGraph,
/// Common types, pre-interned for your convenience.
pub types: CommonTypes<'tcx>,
- pub sess: &'tcx Session,
-
/// Map indicating what traits are in scope for places where this
/// is relevant; generated by resolve.
pub trait_map: TraitMap,
// borrowck. (They are not used during trans, and hence are not
// serialized or needed for cross-crate fns.)
free_region_maps: RefCell<NodeMap<FreeRegionMap>>,
- // FIXME: jroesch make this a refcell
-
- pub tables: RefCell<DepTrackingMap<maps::TypeckTables<'tcx>>>,
-
- /// Maps from a trait item to the trait item "descriptor"
- pub associated_items: RefCell<DepTrackingMap<maps::AssociatedItems<'tcx>>>,
-
- /// Maps from an impl/trait def-id to a list of the def-ids of its items
- pub associated_item_def_ids: RefCell<DepTrackingMap<maps::AssociatedItemDefIds<'tcx>>>,
-
- pub impl_trait_refs: RefCell<DepTrackingMap<maps::ImplTraitRefs<'tcx>>>,
- pub trait_defs: RefCell<DepTrackingMap<maps::TraitDefs<'tcx>>>,
- pub adt_defs: RefCell<DepTrackingMap<maps::AdtDefs<'tcx>>>,
- pub adt_sized_constraint: RefCell<DepTrackingMap<maps::AdtSizedConstraint<'tcx>>>,
-
- /// Maps from the def-id of an item (trait/struct/enum/fn) to its
- /// associated generics and predicates.
- pub generics: RefCell<DepTrackingMap<maps::Generics<'tcx>>>,
- pub predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
-
- /// Maps from the def-id of a trait to the list of
- /// super-predicates. This is a subset of the full list of
- /// predicates. We store these in a separate map because we must
- /// evaluate them even during type conversion, often before the
- /// full predicates are available (note that supertraits have
- /// additional acyclicity requirements).
- pub super_predicates: RefCell<DepTrackingMap<maps::Predicates<'tcx>>>,
pub hir: hir_map::Map<'tcx>,
-
- /// Maps from the def-id of a function/method or const/static
- /// to its MIR. Mutation is done at an item granularity to
- /// allow MIR optimization passes to function and still
- /// access cross-crate MIR (e.g. inlining or const eval).
- ///
- /// Note that cross-crate MIR appears to be always borrowed
- /// (in the `RefCell` sense) to prevent accidental mutation.
- pub mir_map: RefCell<DepTrackingMap<maps::Mir<'tcx>>>,
+ pub maps: maps::Maps<'tcx>,
// Records the free variables refrenced by every closure
// expression. Do not track deps for this, just recompute it from
pub maybe_unused_trait_imports: NodeSet,
- // Records the type of every item.
- pub item_types: RefCell<DepTrackingMap<maps::Types<'tcx>>>,
-
// Internal cache for metadata decoding. No need to track deps on this.
pub rcache: RefCell<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
// Cache for the type-contents routine. FIXME -- track deps?
pub tc_cache: RefCell<FxHashMap<Ty<'tcx>, ty::contents::TypeContents>>,
- // FIXME no dep tracking, but we should be able to remove this
- pub ty_param_defs: RefCell<NodeMap<ty::TypeParameterDef<'tcx>>>,
-
// FIXME dep tracking -- should be harmless enough
pub normalized_cache: RefCell<FxHashMap<Ty<'tcx>, Ty<'tcx>>>,
pub lang_items: middle::lang_items::LanguageItems,
- /// Maps from def-id of a type or region parameter to its
- /// (inferred) variance.
- pub item_variance_map: RefCell<DepTrackingMap<maps::ItemVariances<'tcx>>>,
-
/// True if the variance has been computed yet; false otherwise.
pub variance_computed: Cell<bool>,
- /// Maps a DefId of a type to a list of its inherent impls.
- /// Contains implementations of methods that are inherent to a type.
- /// Methods in these implementations don't need to be exported.
- pub inherent_impls: RefCell<DepTrackingMap<maps::InherentImpls<'tcx>>>,
-
/// Set of used unsafe nodes (functions or blocks). Unsafe nodes not
/// present in this set can be warned about.
pub used_unsafe: RefCell<NodeSet>,
/// about.
pub used_mut_nodes: RefCell<NodeSet>,
- /// Set of trait imports actually used in the method resolution.
- /// This is used for warning unused imports.
- pub used_trait_imports: RefCell<DepTrackingMap<maps::UsedTraitImports<'tcx>>>,
-
/// The set of external nominal types whose implementations have been read.
/// This is used for lazy resolution of methods.
pub populated_external_types: RefCell<DefIdSet>,
/// (i.e., no type or lifetime parameters).
pub fulfilled_predicates: RefCell<traits::GlobalFulfilledPredicates<'tcx>>,
- /// Caches the representation hints for struct definitions.
- repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
-
/// Maps Expr NodeId's to `true` iff `&expr` can have 'static lifetime.
pub rvalue_promotable_to_static: RefCell<NodeMap<bool>>,
- /// Caches CoerceUnsized kinds for impls on custom types.
- pub custom_coerce_unsized_kinds: RefCell<DefIdMap<ty::adjustment::CustomCoerceUnsized>>,
-
- /// Records the type of each closure. The def ID is the ID of the
- /// expression defining the closure.
- pub closure_tys: RefCell<DepTrackingMap<maps::ClosureTypes<'tcx>>>,
-
- /// Records the type of each closure. The def ID is the ID of the
- /// expression defining the closure.
- pub closure_kinds: RefCell<DepTrackingMap<maps::ClosureKinds<'tcx>>>,
-
/// Maps Fn items to a collection of fragment infos.
///
/// The main goal is to identify data (each of which may be moved
stability_interner: RefCell<FxHashSet<&'tcx attr::Stability>>,
layout_interner: RefCell<FxHashSet<&'tcx Layout>>,
+
+ /// A vector of every trait accessible in the whole crate
+ /// (i.e. including those from subcrates). This is used only for
+ /// error reporting, and so is lazily initialised and generally
+ /// shouldn't taint the common path (hence the RefCell).
+ pub all_traits: RefCell<Option<Vec<DefId>>>,
+
+ /// HIR Ty -> Ty lowering cache.
+ pub ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
}
impl<'tcx> GlobalCtxt<'tcx> {
}
}
- pub fn type_parameter_def(self,
- node_id: NodeId)
- -> ty::TypeParameterDef<'tcx>
- {
- self.ty_param_defs.borrow().get(&node_id).unwrap().clone()
- }
-
- pub fn alloc_generics(self, generics: ty::Generics<'gcx>)
- -> &'gcx ty::Generics<'gcx> {
+ pub fn alloc_generics(self, generics: ty::Generics) -> &'gcx ty::Generics {
self.global_arenas.generics.alloc(generics)
}
pub fn alloc_adt_def(self,
did: DefId,
kind: AdtKind,
- discr_ty: Option<attr::IntType>,
variants: Vec<ty::VariantDef>,
repr: ReprOptions)
-> &'gcx ty::AdtDef {
- let discr_ty = discr_ty.unwrap_or(attr::UnsignedInt(ast::UintTy::U8));
- let def = ty::AdtDef::new(self, did, kind, discr_ty, variants, repr);
+ let def = ty::AdtDef::new(self, did, kind, variants, repr);
self.global_arenas.adt_def.alloc(def)
}
/// value (types, substs, etc.) can only be used while `ty::tls` has a valid
/// reference to the context, to allow formatting values that need it.
pub fn create_and_enter<F, R>(s: &'tcx Session,
+ local_providers: ty::maps::Providers<'tcx>,
+ extern_providers: ty::maps::Providers<'tcx>,
arenas: &'tcx GlobalArenas<'tcx>,
arena: &'tcx DroplessArena,
resolutions: ty::Resolutions,
let common_types = CommonTypes::new(&interners);
let dep_graph = hir.dep_graph.clone();
let fulfilled_predicates = traits::GlobalFulfilledPredicates::new(dep_graph.clone());
+ let max_cnum = s.cstore.crates().iter().map(|c| c.as_usize()).max().unwrap_or(0);
+ let mut providers = IndexVec::from_elem_n(extern_providers, max_cnum + 1);
+ providers[LOCAL_CRATE] = local_providers;
tls::enter_global(GlobalCtxt {
+ sess: s,
specializes_cache: RefCell::new(traits::SpecializesCache::new()),
global_arenas: arenas,
global_interners: interners,
named_region_map: named_region_map,
region_maps: region_maps,
free_region_maps: RefCell::new(FxHashMap()),
- item_variance_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
variance_computed: Cell::new(false),
- sess: s,
trait_map: resolutions.trait_map,
- tables: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- impl_trait_refs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- trait_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- adt_defs: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- adt_sized_constraint: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- generics: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- super_predicates: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
fulfilled_predicates: RefCell::new(fulfilled_predicates),
hir: hir,
- mir_map: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
+ maps: maps::Maps::new(dep_graph, providers),
freevars: RefCell::new(resolutions.freevars),
maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports,
- item_types: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
rcache: RefCell::new(FxHashMap()),
tc_cache: RefCell::new(FxHashMap()),
- associated_items: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- associated_item_def_ids: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- ty_param_defs: RefCell::new(NodeMap()),
normalized_cache: RefCell::new(FxHashMap()),
inhabitedness_cache: RefCell::new(FxHashMap()),
lang_items: lang_items,
- inherent_impls: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
used_unsafe: RefCell::new(NodeSet()),
used_mut_nodes: RefCell::new(NodeSet()),
- used_trait_imports: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
populated_external_types: RefCell::new(DefIdSet()),
populated_external_primitive_impls: RefCell::new(DefIdSet()),
stability: RefCell::new(stability),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
- repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
rvalue_promotable_to_static: RefCell::new(NodeMap()),
- custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
- closure_tys: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- closure_kinds: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
fragment_infos: RefCell::new(DefIdMap()),
crate_name: Symbol::intern(crate_name),
data_layout: data_layout,
layout_depth: Cell::new(0),
derive_macros: RefCell::new(NodeMap()),
stability_interner: RefCell::new(FxHashSet()),
+ all_traits: RefCell::new(None),
+ ast_ty_to_ty_cache: RefCell::new(NodeMap()),
}, f)
}
}
}
}
-impl<'a, 'tcx> Lift<'tcx> for &'a BareFnTy<'a> {
- type Lifted = &'tcx BareFnTy<'tcx>;
- fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>)
- -> Option<&'tcx BareFnTy<'tcx>> {
- if tcx.interners.arena.in_arena(*self as *const _) {
- return Some(unsafe { mem::transmute(*self) });
- }
- // Also try in the global tcx if we're not that.
- if !tcx.is_global() {
- self.lift_to_tcx(tcx.global_tcx())
- } else {
- None
- }
- }
-}
-
-
pub mod tls {
use super::{CtxtInterners, GlobalCtxt, TyCtxt};
TyDynamic, TyClosure, TyTuple, TyParam, TyInfer, TyProjection, TyAnon);
println!("Substs interner: #{}", self.interners.substs.borrow().len());
- println!("BareFnTy interner: #{}", self.interners.bare_fn.borrow().len());
println!("Region interner: #{}", self.interners.region.borrow().len());
println!("Stability interner: #{}", self.stability_interner.borrow().len());
println!("Layout interner: #{}", self.layout_interner.borrow().len());
}
}
-impl<'tcx: 'lcx, 'lcx> Borrow<BareFnTy<'lcx>> for Interned<'tcx, BareFnTy<'tcx>> {
- fn borrow<'a>(&'a self) -> &'a BareFnTy<'lcx> {
- self.0
- }
-}
-
impl<'tcx> Borrow<Region> for Interned<'tcx, Region> {
fn borrow<'a>(&'a self) -> &'a Region {
self.0
}
direct_interners!('tcx,
- bare_fn: mk_bare_fn(|fty: &BareFnTy| {
- keep_local(&fty.sig)
- }) -> BareFnTy<'tcx>,
region: mk_region(|r| {
match r {
&ty::ReVar(_) | &ty::ReSkolemized(..) => true,
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
/// Create an unsafe fn ty based on a safe fn ty.
- pub fn safe_to_unsafe_fn_ty(self, bare_fn: &BareFnTy<'tcx>) -> Ty<'tcx> {
- assert_eq!(bare_fn.unsafety, hir::Unsafety::Normal);
- self.mk_fn_ptr(self.mk_bare_fn(ty::BareFnTy {
+ pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
+ assert_eq!(sig.unsafety(), hir::Unsafety::Normal);
+ self.mk_fn_ptr(sig.map_bound(|sig| ty::FnSig {
unsafety: hir::Unsafety::Unsafe,
- abi: bare_fn.abi,
- sig: bare_fn.sig.clone()
+ ..sig
}))
}
pub fn mk_fn_def(self, def_id: DefId,
substs: &'tcx Substs<'tcx>,
- fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+ fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
self.mk_ty(TyFnDef(def_id, substs, fty))
}
- pub fn mk_fn_ptr(self, fty: &'tcx BareFnTy<'tcx>) -> Ty<'tcx> {
+ pub fn mk_fn_ptr(self, fty: PolyFnSig<'tcx>) -> Ty<'tcx> {
self.mk_ty(TyFnPtr(fty))
}
}
}
- pub fn mk_fn_sig<I>(self, inputs: I, output: I::Item, variadic: bool)
+ pub fn mk_fn_sig<I>(self,
+ inputs: I,
+ output: I::Item,
+ variadic: bool,
+ unsafety: hir::Unsafety,
+ abi: abi::Abi)
-> <I::Item as InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>>::Output
where I: Iterator,
I::Item: InternIteratorElement<Ty<'tcx>, ty::FnSig<'tcx>>
{
inputs.chain(iter::once(output)).intern_with(|xs| ty::FnSig {
inputs_and_output: self.intern_type_list(xs),
- variadic: variadic
+ variadic, unsafety, abi
})
}
{
self.mk_substs(iter::once(s).chain(t.into_iter().cloned()).map(Kind::from))
}
-
- /// Obtain the representation annotation for a struct definition.
- pub fn lookup_repr_hints(self, did: DefId) -> Rc<Vec<attr::ReprAttr>> {
- self.repr_hint_cache.memoize(did, || {
- Rc::new(self.get_attrs(did).iter().flat_map(|meta| {
- attr::find_repr_attrs(self.sess.diagnostic(), meta).into_iter()
- }).collect())
- })
- }
}
pub trait InternAs<T: ?Sized, R> {
use hir::def_id::DefId;
use infer::type_variable;
-use ty::{self, BoundRegion, Region, Ty, TyCtxt};
+use ty::{self, BoundRegion, DefIdTree, Region, Ty, TyCtxt};
use std::fmt;
use syntax::abi;
db.span_note(span, "a default was defined here...");
}
None => {
+ let item_def_id = self.parent(expected.def_id).unwrap();
db.note(&format!("a default is defined on `{}`",
- self.item_path_str(expected.def_id)));
+ self.item_path_str(item_def_id)));
}
}
db.span_note(span, "a second default was defined here...");
}
None => {
+ let item_def_id = self.parent(found.def_id).unwrap();
db.note(&format!("a second default is defined on `{}`",
- self.item_path_str(found.def_id)));
+ self.item_path_str(item_def_id)));
}
}
Some(TupleSimplifiedType(tys.len()))
}
ty::TyFnDef(.., ref f) | ty::TyFnPtr(ref f) => {
- Some(FunctionSimplifiedType(f.sig.skip_binder().inputs().len()))
+ Some(FunctionSimplifiedType(f.skip_binder().inputs().len()))
}
ty::TyProjection(_) | ty::TyParam(_) => {
if can_simplify_params {
self.add_tys(&ts[..]);
}
- &ty::TyFnDef(_, substs, ref f) => {
+ &ty::TyFnDef(_, substs, f) => {
self.add_substs(substs);
- self.add_fn_sig(&f.sig);
+ self.add_fn_sig(f);
}
- &ty::TyFnPtr(ref f) => {
- self.add_fn_sig(&f.sig);
+ &ty::TyFnPtr(f) => {
+ self.add_fn_sig(f);
}
}
}
}
}
- fn add_fn_sig(&mut self, fn_sig: &ty::PolyFnSig) {
+ fn add_fn_sig(&mut self, fn_sig: ty::PolyFnSig) {
let mut computation = FlagComputation::new();
computation.add_tys(fn_sig.skip_binder().inputs());
sig.super_fold_with(self)
}
- fn fold_bare_fn_ty(&mut self,
- fty: &'tcx ty::BareFnTy<'tcx>)
- -> &'tcx ty::BareFnTy<'tcx>
- {
- fty.super_fold_with(self)
- }
-
- fn fold_closure_ty(&mut self,
- fty: &ty::ClosureTy<'tcx>)
- -> ty::ClosureTy<'tcx> {
- fty.super_fold_with(self)
- }
-
fn fold_region(&mut self, r: &'tcx ty::Region) -> &'tcx ty::Region {
r.super_fold_with(self)
}
// which contains a Foo<((T, T), (T, T))>
// which contains a Foo<(((T, T), (T, T)), ((T, T), (T, T)))>
// etc.
- let error = format!("reached recursion limit while checking
+ let error = format!("reached recursion limit while checking \
inhabitedness of `{}`", self);
tcx.sess.fatal(&error);
}
} else {
// for local crates, check whether type info is
// available; typeck might not have completed yet
- self.impl_trait_refs.borrow().contains_key(&impl_def_id)
+ self.maps.impl_trait_ref.borrow().contains_key(&impl_def_id)
};
if !use_types {
}
// SIMD vector types.
- ty::TyAdt(def, ..) if def.is_simd() => {
+ ty::TyAdt(def, ..) if def.repr.simd => {
let element = ty.simd_type(tcx);
match *element.layout(infcx)? {
Scalar { value, .. } => {
let (mut min, mut max, mut non_zero) = (i64::max_value(),
i64::min_value(),
true);
- for v in &def.variants {
- let x = v.disr_val as i128 as i64;
+ for discr in def.discriminants(tcx) {
+ let x = discr.to_u128_unchecked() as i64;
if x == 0 { non_zero = false; }
if x < min { min = x; }
if x > max { max = x; }
let fields = def.variants[0].fields.iter().map(|field| {
field.ty(tcx, substs).layout(infcx)
}).collect::<Result<Vec<_>, _>>()?;
- let packed = tcx.lookup_packed(def.did);
let layout = if def.is_union() {
- let mut un = Union::new(dl, packed);
+ let mut un = Union::new(dl, def.repr.packed);
un.extend(dl, fields.iter().map(|&f| Ok(f)), ty)?;
UntaggedUnion { variants: un }
} else {
// non-empty body, explicit discriminants should have
// been rejected by a checker before this point.
for (i, v) in def.variants.iter().enumerate() {
- if i as u128 != v.disr_val {
+ if v.discr != ty::VariantDiscr::Relative(i) {
bug!("non-C-like enum {} with specified discriminants",
tcx.item_path_str(def.did));
}
return Err(LayoutError::SizeOverflow(ty));
}
- let typeck_ity = Integer::from_attr(dl, def.discr_ty);
+ let typeck_ity = Integer::from_attr(dl, def.repr.discr_type());
if typeck_ity < min_ity {
// It is a bug if Layout decided on a greater discriminant size than typeck for
// some reason at this point (based on values discriminant can take on). Mostly
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use dep_graph::{DepNode, DepTrackingMapConfig};
-use hir::def_id::DefId;
+use dep_graph::{DepGraph, DepNode, DepTrackingMap, DepTrackingMapConfig};
+use hir::def_id::{CrateNum, DefId};
+use middle::const_val::ConstVal;
use mir;
-use ty::{self, Ty};
-use util::nodemap::DefIdSet;
+use ty::{self, Ty, TyCtxt};
-use std::cell::RefCell;
-use std::marker::PhantomData;
+use rustc_data_structures::indexed_vec::IndexVec;
+use std::cell::{RefCell, RefMut};
use std::rc::Rc;
-use syntax::attr;
-
-macro_rules! dep_map_ty {
- ($ty_name:ident : $node_name:ident ($key:ty) -> $value:ty) => {
- pub struct $ty_name<'tcx> {
- data: PhantomData<&'tcx ()>
- }
-
- impl<'tcx> DepTrackingMapConfig for $ty_name<'tcx> {
- type Key = $key;
- type Value = $value;
- fn to_dep_node(key: &$key) -> DepNode<DefId> { DepNode::$node_name(*key) }
- }
- }
-}
-
-dep_map_ty! { AssociatedItems: AssociatedItems(DefId) -> ty::AssociatedItem }
-dep_map_ty! { Types: ItemSignature(DefId) -> Ty<'tcx> }
-dep_map_ty! { Generics: ItemSignature(DefId) -> &'tcx ty::Generics<'tcx> }
-dep_map_ty! { Predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
-dep_map_ty! { SuperPredicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx> }
-dep_map_ty! { AssociatedItemDefIds: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>> }
-dep_map_ty! { ImplTraitRefs: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>> }
-dep_map_ty! { TraitDefs: ItemSignature(DefId) -> &'tcx ty::TraitDef }
-dep_map_ty! { AdtDefs: ItemSignature(DefId) -> &'tcx ty::AdtDef }
-dep_map_ty! { AdtSizedConstraint: SizedConstraint(DefId) -> Ty<'tcx> }
-dep_map_ty! { ItemVariances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>> }
-dep_map_ty! { InherentImpls: InherentImpls(DefId) -> Vec<DefId> }
-dep_map_ty! { ReprHints: ReprHints(DefId) -> Rc<Vec<attr::ReprAttr>> }
-dep_map_ty! { Mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>> }
-dep_map_ty! { ClosureKinds: ItemSignature(DefId) -> ty::ClosureKind }
-dep_map_ty! { ClosureTypes: ItemSignature(DefId) -> ty::ClosureTy<'tcx> }
-dep_map_ty! { TypeckTables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx> }
-dep_map_ty! { UsedTraitImports: UsedTraitImports(DefId) -> DefIdSet }
+use syntax_pos::{Span, DUMMY_SP};
+
+trait Key {
+ fn map_crate(&self) -> CrateNum;
+ fn default_span(&self, tcx: TyCtxt) -> Span;
+}
+
+impl Key for CrateNum {
+ fn map_crate(&self) -> CrateNum {
+ *self
+ }
+ fn default_span(&self, _: TyCtxt) -> Span {
+ DUMMY_SP
+ }
+}
+
+impl Key for DefId {
+ fn map_crate(&self) -> CrateNum {
+ self.krate
+ }
+ fn default_span(&self, tcx: TyCtxt) -> Span {
+ tcx.def_span(*self)
+ }
+}
+
+impl Key for (DefId, DefId) {
+ fn map_crate(&self) -> CrateNum {
+ self.0.krate
+ }
+ fn default_span(&self, tcx: TyCtxt) -> Span {
+ self.1.default_span(tcx)
+ }
+}
+
+impl Key for (CrateNum, DefId) {
+ fn map_crate(&self) -> CrateNum {
+ self.0
+ }
+ fn default_span(&self, tcx: TyCtxt) -> Span {
+ self.1.default_span(tcx)
+ }
+}
+
+trait Value<'tcx>: Sized {
+ fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
+}
+
+impl<'tcx, T> Value<'tcx> for T {
+ default fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> T {
+ tcx.sess.abort_if_errors();
+ bug!("Value::from_cycle_error called without errors");
+ }
+}
+
+impl<'tcx, T: Default> Value<'tcx> for T {
+ default fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> T {
+ T::default()
+ }
+}
+
+impl<'tcx> Value<'tcx> for Ty<'tcx> {
+ fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
+ tcx.types.err
+ }
+}
+
+pub struct CycleError<'a> {
+ span: Span,
+ cycle: RefMut<'a, [(Span, Query)]>
+}
+
+impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
+ pub fn report_cycle(self, CycleError { span, cycle }: CycleError) {
+ assert!(!cycle.is_empty());
+
+ let mut err = struct_span_err!(self.sess, span, E0391,
+ "unsupported cyclic reference between types/traits detected");
+ err.span_label(span, &format!("cyclic reference"));
+
+ err.span_note(cycle[0].0, &format!("the cycle begins when {}...",
+ cycle[0].1.describe(self)));
+
+ for &(span, ref query) in &cycle[1..] {
+ err.span_note(span, &format!("...which then requires {}...",
+ query.describe(self)));
+ }
+
+ err.note(&format!("...which then again requires {}, completing the cycle.",
+ cycle[0].1.describe(self)));
+
+ err.emit();
+ }
+
+ fn cycle_check<F, R>(self, span: Span, query: Query, compute: F)
+ -> Result<R, CycleError<'a>>
+ where F: FnOnce() -> R
+ {
+ {
+ let mut stack = self.maps.query_stack.borrow_mut();
+ if let Some((i, _)) = stack.iter().enumerate().rev()
+ .find(|&(_, &(_, ref q))| *q == query) {
+ return Err(CycleError {
+ span: span,
+ cycle: RefMut::map(stack, |stack| &mut stack[i..])
+ });
+ }
+ stack.push((span, query));
+ }
+
+ let result = compute();
+
+ self.maps.query_stack.borrow_mut().pop();
+
+ Ok(result)
+ }
+}
+
+trait QueryDescription: DepTrackingMapConfig {
+ fn describe(tcx: TyCtxt, key: Self::Key) -> String;
+}
+
+impl<M: DepTrackingMapConfig<Key=DefId>> QueryDescription for M {
+ default fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+ format!("processing `{}`", tcx.item_path_str(def_id))
+ }
+}
+
+impl<'tcx> QueryDescription for queries::super_predicates<'tcx> {
+ fn describe(tcx: TyCtxt, def_id: DefId) -> String {
+ format!("computing the supertraits of `{}`",
+ tcx.item_path_str(def_id))
+ }
+}
+
+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();
+ format!("computing the bounds for type parameter `{}`",
+ tcx.hir.ty_param_name(id))
+ }
+}
+
+impl<'tcx> QueryDescription for queries::coherent_trait<'tcx> {
+ fn describe(tcx: TyCtxt, (_, def_id): (CrateNum, DefId)) -> String {
+ format!("coherence checking all impls of trait `{}`",
+ tcx.item_path_str(def_id))
+ }
+}
+
+impl<'tcx> QueryDescription for queries::coherent_inherent_impls<'tcx> {
+ fn describe(_: TyCtxt, _: CrateNum) -> String {
+ format!("coherence checking all inherent impls")
+ }
+}
+
+macro_rules! define_maps {
+ (<$tcx:tt>
+ $($(#[$attr:meta])*
+ pub $name:ident: $node:ident($K:ty) -> $V:ty),*) => {
+ pub struct Maps<$tcx> {
+ providers: IndexVec<CrateNum, Providers<$tcx>>,
+ query_stack: RefCell<Vec<(Span, Query)>>,
+ $($(#[$attr])* pub $name: RefCell<DepTrackingMap<queries::$name<$tcx>>>),*
+ }
+
+ impl<$tcx> Maps<$tcx> {
+ pub fn new(dep_graph: DepGraph,
+ providers: IndexVec<CrateNum, Providers<$tcx>>)
+ -> Self {
+ Maps {
+ providers,
+ query_stack: RefCell::new(vec![]),
+ $($name: RefCell::new(DepTrackingMap::new(dep_graph.clone()))),*
+ }
+ }
+ }
+
+ #[allow(bad_style)]
+ #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+ pub enum Query {
+ $($(#[$attr])* $name($K)),*
+ }
+
+ impl Query {
+ pub fn describe(&self, tcx: TyCtxt) -> String {
+ match *self {
+ $(Query::$name(key) => queries::$name::describe(tcx, key)),*
+ }
+ }
+ }
+
+ pub mod queries {
+ use std::marker::PhantomData;
+
+ $(#[allow(bad_style)]
+ pub struct $name<$tcx> {
+ data: PhantomData<&$tcx ()>
+ })*
+ }
+
+ $(impl<$tcx> DepTrackingMapConfig for queries::$name<$tcx> {
+ type Key = $K;
+ type Value = $V;
+
+ #[allow(unused)]
+ fn to_dep_node(key: &$K) -> DepNode<DefId> {
+ use dep_graph::DepNode::*;
+
+ $node(*key)
+ }
+ }
+ impl<'a, $tcx, 'lcx> queries::$name<$tcx> {
+ fn try_get_with<F, R>(tcx: TyCtxt<'a, $tcx, 'lcx>,
+ mut span: Span,
+ key: $K,
+ f: F)
+ -> Result<R, CycleError<'a>>
+ where F: FnOnce(&$V) -> R
+ {
+ if let Some(result) = tcx.maps.$name.borrow().get(&key) {
+ return Ok(f(result));
+ }
+
+ // FIXME(eddyb) Get more valid Span's on queries.
+ if span == DUMMY_SP {
+ span = key.default_span(tcx);
+ }
+
+ let _task = tcx.dep_graph.in_task(Self::to_dep_node(&key));
+
+ let result = tcx.cycle_check(span, Query::$name(key), || {
+ let provider = tcx.maps.providers[key.map_crate()].$name;
+ provider(tcx.global_tcx(), key)
+ })?;
+
+ Ok(f(&tcx.maps.$name.borrow_mut().entry(key).or_insert(result)))
+ }
+
+ pub fn try_get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K)
+ -> Result<$V, CycleError<'a>> {
+ Self::try_get_with(tcx, span, key, Clone::clone)
+ }
+
+ $(#[$attr])*
+ pub fn get(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) -> $V {
+ Self::try_get(tcx, span, key).unwrap_or_else(|e| {
+ tcx.report_cycle(e);
+ Value::from_cycle_error(tcx.global_tcx())
+ })
+ }
+
+ pub fn force(tcx: TyCtxt<'a, $tcx, 'lcx>, span: Span, key: $K) {
+ // FIXME(eddyb) Move away from using `DepTrackingMap`
+ // so we don't have to explicitly ignore a false edge:
+ // we can't observe a value dependency, only side-effects,
+ // through `force`, and once everything has been updated,
+ // perhaps only diagnostics, if those, will remain.
+ let _ignore = tcx.dep_graph.in_ignore();
+ match Self::try_get_with(tcx, span, key, |_| ()) {
+ Ok(()) => {}
+ Err(e) => tcx.report_cycle(e)
+ }
+ }
+ })*
+
+ pub struct Providers<$tcx> {
+ $(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $V),*
+ }
+
+ impl<$tcx> Copy for Providers<$tcx> {}
+ impl<$tcx> Clone for Providers<$tcx> {
+ fn clone(&self) -> Self { *self }
+ }
+
+ impl<$tcx> Default for Providers<$tcx> {
+ fn default() -> Self {
+ $(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $V {
+ bug!("tcx.maps.{}({:?}) unsupported by its crate",
+ stringify!($name), key);
+ })*
+ Providers { $($name),* }
+ }
+ }
+ }
+}
+
+// Each of these maps also corresponds to a method on a
+// `Provider` trait for requesting a value of that type,
+// and a method on `Maps` itself for doing that in a
+// a way that memoizes and does dep-graph tracking,
+// wrapping around the actual chain of providers that
+// the driver creates (using several `rustc_*` crates).
+define_maps! { <'tcx>
+ /// Records the type of every item.
+ pub ty: ItemSignature(DefId) -> Ty<'tcx>,
+
+ /// Maps from the def-id of an item (trait/struct/enum/fn) to its
+ /// associated generics and predicates.
+ pub generics: ItemSignature(DefId) -> &'tcx ty::Generics,
+ pub predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
+
+ /// Maps from the def-id of a trait to the list of
+ /// super-predicates. This is a subset of the full list of
+ /// predicates. We store these in a separate map because we must
+ /// evaluate them even during type conversion, often before the
+ /// full predicates are available (note that supertraits have
+ /// additional acyclicity requirements).
+ pub super_predicates: ItemSignature(DefId) -> ty::GenericPredicates<'tcx>,
+
+ /// To avoid cycles within the predicates of a single item we compute
+ /// per-type-parameter predicates for resolving `T::AssocTy`.
+ pub type_param_predicates: TypeParamPredicates((DefId, DefId))
+ -> ty::GenericPredicates<'tcx>,
+
+ pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
+ pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
+ pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
+
+ /// Maps from def-id of a type or region parameter to its
+ /// (inferred) variance.
+ pub variances: ItemSignature(DefId) -> Rc<Vec<ty::Variance>>,
+
+ /// Maps from an impl/trait def-id to a list of the def-ids of its items
+ pub associated_item_def_ids: AssociatedItemDefIds(DefId) -> Rc<Vec<DefId>>,
+
+ /// Maps from a trait item to the trait item "descriptor"
+ pub associated_item: AssociatedItems(DefId) -> ty::AssociatedItem,
+
+ pub impl_trait_ref: ItemSignature(DefId) -> Option<ty::TraitRef<'tcx>>,
+
+ /// Maps a DefId of a type to a list of its inherent impls.
+ /// Contains implementations of methods that are inherent to a type.
+ /// Methods in these implementations don't need to be exported.
+ pub inherent_impls: InherentImpls(DefId) -> Vec<DefId>,
+
+ /// Maps from the def-id of a function/method or const/static
+ /// to its MIR. Mutation is done at an item granularity to
+ /// allow MIR optimization passes to function and still
+ /// access cross-crate MIR (e.g. inlining or const eval).
+ ///
+ /// Note that cross-crate MIR appears to be always borrowed
+ /// (in the `RefCell` sense) to prevent accidental mutation.
+ pub mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
+
+ /// Maps DefId's that have an associated Mir to the result
+ /// of the MIR qualify_consts pass. The actual meaning of
+ /// the value isn't known except to the pass itself.
+ pub mir_const_qualif: Mir(DefId) -> u8,
+
+ /// Records the type of each closure. The def ID is the ID of the
+ /// expression defining the closure.
+ pub closure_kind: ItemSignature(DefId) -> ty::ClosureKind,
+
+ /// Records the type of each closure. The def ID is the ID of the
+ /// expression defining the closure.
+ pub closure_type: ItemSignature(DefId) -> ty::PolyFnSig<'tcx>,
+
+ /// Caches CoerceUnsized kinds for impls on custom types.
+ pub custom_coerce_unsized_kind: ItemSignature(DefId)
+ -> ty::adjustment::CustomCoerceUnsized,
+
+ pub typeck_tables: TypeckTables(DefId) -> &'tcx ty::TypeckTables<'tcx>,
+
+ pub coherent_trait: coherent_trait_dep_node((CrateNum, DefId)) -> (),
+
+ pub coherent_inherent_impls: coherent_inherent_impls_dep_node(CrateNum) -> (),
+
+ /// Results of evaluating monomorphic constants embedded in
+ /// other items, such as enum variant explicit discriminants.
+ pub monomorphic_const_eval: MonomorphicConstEval(DefId) -> Result<ConstVal<'tcx>, ()>
+}
+
+fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> {
+ DepNode::CoherenceCheckTrait(def_id)
+}
+
+fn coherent_inherent_impls_dep_node(_: CrateNum) -> DepNode<DefId> {
+ DepNode::Coherence
+}
use hir::{map as hir_map, FreevarMap, TraitMap};
use middle;
use hir::def::{Def, CtorKind, ExportMap};
-use hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
+use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
+use middle::const_val::ConstVal;
use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use middle::region::{CodeExtent, ROOT_CODE_EXTENT};
+use middle::resolve_lifetime::ObjectLifetimeDefault;
use mir::Mir;
use traits;
use ty;
use ty::subst::{Subst, Substs};
+use ty::util::IntTypeExt;
use ty::walk::TypeWalker;
use util::common::MemoizationMap;
-use util::nodemap::{NodeSet, NodeMap, FxHashMap};
+use util::nodemap::{NodeSet, FxHashMap};
use serialize::{self, Encodable, Encoder};
use std::borrow::Cow;
use std::cell::{Cell, RefCell, Ref};
+use std::collections::BTreeMap;
use std::hash::{Hash, Hasher};
use std::ops::Deref;
use std::rc::Rc;
use syntax::attr;
use syntax::symbol::{Symbol, InternedString};
use syntax_pos::{DUMMY_SP, Span};
+use rustc_const_math::ConstInt;
use rustc_data_structures::accumulate_vec::IntoIter as AccIntoIter;
use hir::itemlikevisit::ItemLikeVisitor;
pub use self::sty::{Binder, DebruijnIndex};
-pub use self::sty::{BareFnTy, FnSig, PolyFnSig};
-pub use self::sty::{ClosureTy, InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
+pub use self::sty::{FnSig, PolyFnSig};
+pub use self::sty::{InferTy, ParamTy, ProjectionTy, ExistentialPredicate};
pub use self::sty::{ClosureSubsts, TypeAndMut};
pub use self::sty::{TraitRef, TypeVariants, PolyTraitRef};
pub use self::sty::{ExistentialTraitRef, PolyExistentialTraitRef};
pub use self::trait_def::{TraitDef, TraitFlags};
+pub use self::maps::queries;
+
pub mod adjustment;
pub mod cast;
pub mod error;
mod structural_impls;
mod sty;
-pub type Disr = u128;
-
// Data types
/// The complete set of all analyses described in this module. This is
/// produced by the driver and fed to trans and later passes.
#[derive(Clone)]
-pub struct CrateAnalysis<'tcx> {
+pub struct CrateAnalysis {
pub export_map: ExportMap,
pub access_levels: middle::privacy::AccessLevels,
pub reachable: NodeSet,
pub name: String,
pub glob_map: Option<hir::GlobMap>,
- pub hir_ty_to_ty: NodeMap<Ty<'tcx>>,
}
#[derive(Clone)]
UintType(ast::UintTy),
}
-#[derive(Clone, RustcEncodable, RustcDecodable)]
-pub struct TypeParameterDef<'tcx> {
+#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
+pub struct TypeParameterDef {
pub name: Name,
pub def_id: DefId,
pub index: u32,
- pub default_def_id: DefId, // for use in error reporing about defaults
- pub default: Option<Ty<'tcx>>,
+ pub has_default: bool,
+ pub object_lifetime_default: ObjectLifetimeDefault,
/// `pure_wrt_drop`, set by the (unsafe) `#[may_dangle]` attribute
/// on generic parameter `T`, asserts data behind the parameter
/// Information about the formal type/lifetime parameters associated
/// with an item or method. Analogous to hir::Generics.
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
-pub struct Generics<'tcx> {
+pub struct Generics {
pub parent: Option<DefId>,
pub parent_regions: u32,
pub parent_types: u32,
pub regions: Vec<RegionParameterDef>,
- pub types: Vec<TypeParameterDef<'tcx>>,
+ pub types: Vec<TypeParameterDef>,
+
+ /// Reverse map to each `TypeParameterDef`'s `index` field, from
+ /// `def_id.index` (`def_id.krate` is the same as the item's).
+ pub type_param_to_index: BTreeMap<DefIndex, u32>,
+
pub has_self: bool,
}
-impl<'tcx> Generics<'tcx> {
+impl Generics {
pub fn parent_count(&self) -> usize {
self.parent_regions as usize + self.parent_types as usize
}
}
pub fn region_param(&self, param: &EarlyBoundRegion) -> &RegionParameterDef {
+ assert_eq!(self.parent_count(), 0);
&self.regions[param.index as usize - self.has_self as usize]
}
- pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef<'tcx> {
+ pub fn type_param(&self, param: &ParamTy) -> &TypeParameterDef {
+ assert_eq!(self.parent_count(), 0);
&self.types[param.idx as usize - self.has_self as usize - self.regions.len()]
}
}
/// Bounds on generics.
-#[derive(Clone)]
+#[derive(Clone, Default)]
pub struct GenericPredicates<'tcx> {
pub parent: Option<DefId>,
pub predicates: Vec<Predicate<'tcx>>,
}
}
-impl<'tcx> TraitRef<'tcx> {
- pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> {
- TraitRef { def_id: def_id, substs: substs }
- }
-
- pub fn self_ty(&self) -> Ty<'tcx> {
- self.substs.type_at(0)
- }
-
- pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
- // Select only the "input types" from a trait-reference. For
- // now this is all the types that appear in the
- // trait-reference, but it should eventually exclude
- // associated types.
- self.substs.types()
- }
-}
-
/// When type checking, we use the `ParameterEnvironment` to track
/// details about the type/lifetime parameters that are in scope.
/// It primarily stores the bounds information.
const IS_DTORCK = 1 << 1, // is this a dtorck type?
const IS_DTORCK_VALID = 1 << 2,
const IS_PHANTOM_DATA = 1 << 3,
- const IS_SIMD = 1 << 4,
- const IS_FUNDAMENTAL = 1 << 5,
- const IS_UNION = 1 << 6,
- const IS_BOX = 1 << 7,
+ const IS_FUNDAMENTAL = 1 << 4,
+ const IS_UNION = 1 << 5,
+ const IS_BOX = 1 << 6,
+ const IS_DTOR_VALID = 1 << 7,
}
}
/// this is the DefId of the struct's ctor.
pub did: DefId,
pub name: Name, // struct's name if this is a struct
- pub disr_val: Disr,
+ pub discr: VariantDiscr,
pub fields: Vec<FieldDef>,
pub ctor_kind: CtorKind,
}
+#[derive(Copy, Clone, Debug, PartialEq, Eq, RustcEncodable, RustcDecodable)]
+pub enum VariantDiscr {
+ /// Explicit value for this variant, i.e. `X = 123`.
+ /// The `DefId` corresponds to the embedded constant.
+ Explicit(DefId),
+
+ /// The previous variant's discriminant plus one.
+ /// For efficiency reasons, the distance from the
+ /// last `Explicit` discriminant is being stored,
+ /// or `0` for the first variant, if it has none.
+ Relative(usize),
+}
+
#[derive(Debug)]
pub struct FieldDef {
pub did: DefId,
/// table.
pub struct AdtDef {
pub did: DefId,
- /// Type of the discriminant
- ///
- /// Note, that this is the type specified in `repr()` or a default type of some sort, and might
- /// not match the actual type that layout algorithm decides to use when translating this type
- /// into LLVM. That being said, layout algorithm may not use a type larger than specified here.
- pub discr_ty: attr::IntType,
pub variants: Vec<VariantDef>,
destructor: Cell<Option<DefId>>,
flags: Cell<AdtFlags>,
}
impl ReprOptions {
- pub fn new<'a, 'gcx, 'tcx>(tcx: &TyCtxt<'a, 'gcx, 'tcx>, did: DefId) -> ReprOptions {
+ pub fn new(tcx: TyCtxt, did: DefId) -> ReprOptions {
let mut ret = ReprOptions::default();
- let attrs = tcx.lookup_repr_hints(did);
- for r in attrs.iter() {
- match *r {
- attr::ReprExtern => ret.c = true,
- attr::ReprPacked => ret.packed = true,
- attr::ReprSimd => ret.simd = true,
- attr::ReprInt(i) => ret.int = Some(i),
- attr::ReprAny => (),
+
+ for attr in tcx.get_attrs(did).iter() {
+ for r in attr::find_repr_attrs(tcx.sess.diagnostic(), attr) {
+ match r {
+ attr::ReprExtern => ret.c = true,
+ attr::ReprPacked => ret.packed = true,
+ attr::ReprSimd => ret.simd = true,
+ attr::ReprInt(i) => ret.int = Some(i),
+ }
}
}
+
+ // FIXME(eddyb) This is deprecated and should be removed.
+ if tcx.has_attr(did, "simd") {
+ ret.simd = true;
+ }
+
ret
}
+
+ pub fn discr_type(&self) -> attr::IntType {
+ self.int.unwrap_or(attr::SignedInt(ast::IntTy::Is))
+ }
}
impl<'a, 'gcx, 'tcx> AdtDef {
- fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>,
+ fn new(tcx: TyCtxt,
did: DefId,
kind: AdtKind,
- discr_ty: attr::IntType,
variants: Vec<VariantDef>,
repr: ReprOptions) -> Self {
let mut flags = AdtFlags::NO_ADT_FLAGS;
if attr::contains_name(&attrs, "fundamental") {
flags = flags | AdtFlags::IS_FUNDAMENTAL;
}
- if tcx.lookup_simd(did) {
- flags = flags | AdtFlags::IS_SIMD;
- }
if Some(did) == tcx.lang_items.phantom_data() {
flags = flags | AdtFlags::IS_PHANTOM_DATA;
}
}
AdtDef {
did: did,
- discr_ty: discr_ty,
variants: variants,
flags: Cell::new(flags),
destructor: Cell::new(None),
self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL)
}
- #[inline]
- pub fn is_simd(&self) -> bool {
- self.flags.get().intersects(AdtFlags::IS_SIMD)
- }
-
/// Returns true if this is PhantomData<T>.
#[inline]
pub fn is_phantom_data(&self) -> bool {
}
/// Returns whether this type has a destructor.
- pub fn has_dtor(&self) -> bool {
- self.destructor.get().is_some()
+ pub fn has_dtor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+ self.destructor(tcx).is_some()
}
/// Asserts this is a struct and returns the struct's unique
}
}
- pub fn destructor(&self) -> Option<DefId> {
- self.destructor.get()
+ pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
+ if self.flags.get().intersects(AdtFlags::IS_DTOR_VALID) {
+ return self.destructor.get();
+ }
+
+ let dtor = self.destructor_uncached(tcx);
+ self.destructor.set(dtor);
+ self.flags.set(self.flags.get() | AdtFlags::IS_DTOR_VALID);
+
+ dtor
}
- pub fn set_destructor(&self, dtor: DefId) {
- self.destructor.set(Some(dtor));
+ fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
+ let drop_trait = if let Some(def_id) = tcx.lang_items.drop_trait() {
+ def_id
+ } else {
+ return None;
+ };
+
+ queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, drop_trait));
+
+ let mut dtor = None;
+ let ty = tcx.item_type(self.did);
+ tcx.lookup_trait_def(drop_trait).for_each_relevant_impl(tcx, ty, |def_id| {
+ if let Some(item) = tcx.associated_items(def_id).next() {
+ dtor = Some(item.def_id);
+ }
+ });
+
+ dtor
+ }
+
+ pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+ -> impl Iterator<Item=ConstInt> + 'a {
+ let repr_type = self.repr.discr_type();
+ let initial = repr_type.initial_discriminant(tcx.global_tcx());
+ let mut prev_discr = None::<ConstInt>;
+ self.variants.iter().map(move |v| {
+ let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
+ if let VariantDiscr::Explicit(expr_did) = v.discr {
+ match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
+ Ok(ConstVal::Integral(v)) => {
+ discr = v;
+ }
+ _ => {}
+ }
+ }
+ prev_discr = Some(discr);
+
+ discr
+ })
}
/// Returns a simpler type such that `Self: Sized` if and only
stack: &mut Vec<DefId>)
-> Ty<'tcx>
{
- if let Some(ty) = tcx.adt_sized_constraint.borrow().get(&self.did) {
+ if let Some(ty) = tcx.maps.adt_sized_constraint.borrow().get(&self.did) {
return ty;
}
//
// Consider the type as Sized in the meanwhile to avoid
// further errors.
- tcx.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err);
+ tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, tcx.types.err);
return tcx.types.err;
}
_ => tcx.intern_tup(&tys[..], false)
};
- let old = tcx.adt_sized_constraint.borrow().get(&self.did).cloned();
+ let old = tcx.maps.adt_sized_constraint.borrow().get(&self.did).cloned();
match old {
Some(old_ty) => {
debug!("calculate_sized_constraint: {:?} recurred", self);
}
None => {
debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
- tcx.adt_sized_constraint.borrow_mut().insert(self.did, ty);
+ tcx.maps.adt_sized_constraint.borrow_mut().insert(self.did, ty);
ty
}
}
}
}
-/// Helper for looking things up in the various maps that are populated during
-/// typeck::collect (e.g., `tcx.associated_items`, `tcx.types`, etc). All of
-/// these share the pattern that if the id is local, it should have been loaded
-/// into the map by the `typeck::collect` phase. If the def-id is external,
-/// then we have to go consult the crate loading code (and cache the result for
-/// the future).
-fn lookup_locally_or_in_crate_store<M, F>(descr: &str,
- def_id: DefId,
- map: &M,
- load_external: F)
- -> M::Value where
- M: MemoizationMap<Key=DefId>,
- F: FnOnce() -> M::Value,
-{
- map.memoize(def_id, || {
- if def_id.is_local() {
- bug!("No def'n found for {:?} in tcx.{}", def_id, descr);
- }
- load_external()
- })
-}
-
impl BorrowKind {
pub fn from_mutbl(m: hir::Mutability) -> BorrowKind {
match m {
}
pub fn item_tables(self, def_id: DefId) -> &'gcx TypeckTables<'gcx> {
- self.tables.memoize(def_id, || {
- if def_id.is_local() {
- // Closures' tables come from their outermost function,
- // as they are part of the same "inference environment".
- let outer_def_id = self.closure_base_def_id(def_id);
- if outer_def_id != def_id {
- return self.item_tables(outer_def_id);
- }
-
- bug!("No def'n found for {:?} in tcx.tables", def_id);
- }
-
- // Cross-crate side-tables only exist alongside serialized HIR.
- self.sess.cstore.maybe_get_item_body(self.global_tcx(), def_id).map(|_| {
- self.tables.borrow()[&def_id]
- }).unwrap_or_else(|| {
- bug!("tcx.item_tables({:?}): missing from metadata", def_id)
- })
- })
+ queries::typeck_tables::get(self, DUMMY_SP, def_id)
}
pub fn expr_span(self, id: NodeId) -> Span {
}
pub fn custom_coerce_unsized_kind(self, did: DefId) -> adjustment::CustomCoerceUnsized {
- self.custom_coerce_unsized_kinds.memoize(did, || {
- let (kind, src) = if did.krate != LOCAL_CRATE {
- (self.sess.cstore.custom_coerce_unsized_kind(did), "external")
- } else {
- (None, "local")
- };
-
- match kind {
- Some(kind) => kind,
- None => {
- bug!("custom_coerce_unsized_kind: \
- {} impl `{}` is missing its kind",
- src, self.item_path_str(did));
- }
- }
- })
+ queries::custom_coerce_unsized_kind::get(self, DUMMY_SP, did)
}
pub fn associated_item(self, def_id: DefId) -> AssociatedItem {
- self.associated_items.memoize(def_id, || {
- if !def_id.is_local() {
- return self.sess.cstore.associated_item(def_id)
- .expect("missing AssociatedItem in metadata");
- }
+ if !def_id.is_local() {
+ return queries::associated_item::get(self, DUMMY_SP, def_id);
+ }
+ self.maps.associated_item.memoize(def_id, || {
// When the user asks for a given associated item, we
// always go ahead and convert all the associated items in
// the container. Note that we are also careful only to
self.associated_item_from_impl_item_ref(parent_def_id,
impl_trait_ref.is_some(),
impl_item_ref);
- self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
+ self.maps.associated_item.borrow_mut()
+ .insert(assoc_item.def_id, assoc_item);
}
}
for trait_item_ref in trait_item_refs {
let assoc_item =
self.associated_item_from_trait_item_ref(parent_def_id, trait_item_ref);
- self.associated_items.borrow_mut().insert(assoc_item.def_id, assoc_item);
+ self.maps.associated_item.borrow_mut()
+ .insert(assoc_item.def_id, assoc_item);
}
}
// memoize wants us to return something, so return
// the one we generated for this def-id
- *self.associated_items.borrow().get(&def_id).unwrap()
+ *self.maps.associated_item.borrow().get(&def_id).unwrap()
})
}
}
pub fn associated_item_def_ids(self, def_id: DefId) -> Rc<Vec<DefId>> {
- self.associated_item_def_ids.memoize(def_id, || {
- if !def_id.is_local() {
- return Rc::new(self.sess.cstore.associated_item_def_ids(def_id));
- }
+ if !def_id.is_local() {
+ return queries::associated_item_def_ids::get(self, DUMMY_SP, def_id);
+ }
+ self.maps.associated_item_def_ids.memoize(def_id, || {
let id = self.hir.as_local_node_id(def_id).unwrap();
let item = self.hir.expect_item(id);
let vec: Vec<_> = match item.node {
/// Returns the trait-ref corresponding to a given impl, or None if it is
/// an inherent impl.
pub fn impl_trait_ref(self, id: DefId) -> Option<TraitRef<'gcx>> {
- lookup_locally_or_in_crate_store(
- "impl_trait_refs", id, &self.impl_trait_refs,
- || self.sess.cstore.impl_trait_ref(self.global_tcx(), id))
+ queries::impl_trait_ref::get(self, DUMMY_SP, id)
}
// Returns `ty::VariantDef` if `def` refers to a struct,
// If the given item is in an external crate, looks up its type and adds it to
// the type cache. Returns the type parameters and type.
pub fn item_type(self, did: DefId) -> Ty<'gcx> {
- lookup_locally_or_in_crate_store(
- "item_types", did, &self.item_types,
- || self.sess.cstore.item_type(self.global_tcx(), did))
+ queries::ty::get(self, DUMMY_SP, did)
}
/// Given the did of a trait, returns its canonical trait ref.
pub fn lookup_trait_def(self, did: DefId) -> &'gcx TraitDef {
- lookup_locally_or_in_crate_store(
- "trait_defs", did, &self.trait_defs,
- || self.alloc_trait_def(self.sess.cstore.trait_def(self.global_tcx(), did))
- )
+ queries::trait_def::get(self, DUMMY_SP, did)
}
/// Given the did of an ADT, return a reference to its definition.
pub fn lookup_adt_def(self, did: DefId) -> &'gcx AdtDef {
- lookup_locally_or_in_crate_store(
- "adt_defs", did, &self.adt_defs,
- || self.sess.cstore.adt_def(self.global_tcx(), did))
+ queries::adt_def::get(self, DUMMY_SP, did)
}
/// Given the did of an item, returns its generics.
- pub fn item_generics(self, did: DefId) -> &'gcx Generics<'gcx> {
- lookup_locally_or_in_crate_store(
- "generics", did, &self.generics,
- || self.alloc_generics(self.sess.cstore.item_generics(self.global_tcx(), did)))
+ pub fn item_generics(self, did: DefId) -> &'gcx Generics {
+ queries::generics::get(self, DUMMY_SP, did)
}
/// Given the did of an item, returns its full set of predicates.
pub fn item_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
- lookup_locally_or_in_crate_store(
- "predicates", did, &self.predicates,
- || self.sess.cstore.item_predicates(self.global_tcx(), did))
+ queries::predicates::get(self, DUMMY_SP, did)
}
/// Given the did of a trait, returns its superpredicates.
pub fn item_super_predicates(self, did: DefId) -> GenericPredicates<'gcx> {
- lookup_locally_or_in_crate_store(
- "super_predicates", did, &self.super_predicates,
- || self.sess.cstore.item_super_predicates(self.global_tcx(), did))
+ queries::super_predicates::get(self, DUMMY_SP, did)
}
/// Given the did of an item, returns its MIR, borrowed immutably.
pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
- lookup_locally_or_in_crate_store("mir_map", did, &self.mir_map, || {
- let mir = self.sess.cstore.get_item_mir(self.global_tcx(), did);
- let mir = self.alloc_mir(mir);
-
- // Perma-borrow MIR from extern crates to prevent mutation.
- mem::forget(mir.borrow());
-
- mir
- }).borrow()
+ queries::mir::get(self, DUMMY_SP, did).borrow()
}
/// If `type_needs_drop` returns true, then `ty` is definitely
self.get_attrs(did).iter().any(|item| item.check_name(attr))
}
- /// Determine whether an item is annotated with `#[repr(packed)]`
- pub fn lookup_packed(self, did: DefId) -> bool {
- self.lookup_repr_hints(did).contains(&attr::ReprPacked)
- }
-
- /// Determine whether an item is annotated with `#[simd]`
- pub fn lookup_simd(self, did: DefId) -> bool {
- self.has_attr(did, "simd")
- || self.lookup_repr_hints(did).contains(&attr::ReprSimd)
- }
-
pub fn item_variances(self, item_id: DefId) -> Rc<Vec<ty::Variance>> {
- lookup_locally_or_in_crate_store(
- "item_variance_map", item_id, &self.item_variance_map,
- || Rc::new(self.sess.cstore.item_variances(item_id)))
+ queries::variances::get(self, DUMMY_SP, item_id)
}
pub fn trait_has_default_impl(self, trait_def_id: DefId) -> bool {
- self.populate_implementations_for_trait_if_necessary(trait_def_id);
-
let def = self.lookup_trait_def(trait_def_id);
def.flags.get().intersects(TraitFlags::HAS_DEFAULT_IMPL)
}
- /// Records a trait-to-implementation mapping.
- pub fn record_trait_has_default_impl(self, trait_def_id: DefId) {
- let def = self.lookup_trait_def(trait_def_id);
- def.flags.set(def.flags.get() | TraitFlags::HAS_DEFAULT_IMPL)
- }
-
/// Populates the type context with all the inherent implementations for
/// the given type if necessary.
pub fn populate_inherent_implementations_for_type_if_necessary(self,
+ span: Span,
type_id: DefId) {
if type_id.is_local() {
+ // Make sure coherence of inherent impls ran already.
+ ty::queries::coherent_inherent_impls::force(self, span, LOCAL_CRATE);
return
}
let inherent_impls = self.sess.cstore.inherent_implementations_for_type(type_id);
- self.inherent_impls.borrow_mut().insert(type_id, inherent_impls);
+ self.maps.inherent_impls.borrow_mut().insert(type_id, inherent_impls);
self.populated_external_types.borrow_mut().insert(type_id);
}
let _ignore = self.dep_graph.in_ignore();
let def = self.lookup_trait_def(trait_id);
- if def.flags.get().intersects(TraitFlags::IMPLS_VALID) {
+ if def.flags.get().intersects(TraitFlags::HAS_REMOTE_IMPLS) {
return;
}
debug!("populate_implementations_for_trait_if_necessary: searching for {:?}", def);
- if self.sess.cstore.is_defaulted_trait(trait_id) {
- self.record_trait_has_default_impl(trait_id);
- }
-
for impl_def_id in self.sess.cstore.implementations_of_trait(Some(trait_id)) {
let trait_ref = self.impl_trait_ref(impl_def_id).unwrap();
def.record_remote_impl(self, impl_def_id, trait_ref, parent);
}
- def.flags.set(def.flags.get() | TraitFlags::IMPLS_VALID);
+ def.flags.set(def.flags.get() | TraitFlags::HAS_REMOTE_IMPLS);
}
pub fn closure_kind(self, def_id: DefId) -> ty::ClosureKind {
- // If this is a local def-id, it should be inserted into the
- // tables by typeck; else, it will be retreived from
- // the external crate metadata.
- if let Some(&kind) = self.closure_kinds.borrow().get(&def_id) {
- return kind;
- }
-
- let kind = self.sess.cstore.closure_kind(def_id);
- self.closure_kinds.borrow_mut().insert(def_id, kind);
- kind
+ queries::closure_kind::get(self, DUMMY_SP, def_id)
}
- pub fn closure_type(self,
- def_id: DefId,
- substs: ClosureSubsts<'tcx>)
- -> ty::ClosureTy<'tcx>
- {
- // If this is a local def-id, it should be inserted into the
- // tables by typeck; else, it will be retreived from
- // the external crate metadata.
- if let Some(ty) = self.closure_tys.borrow().get(&def_id) {
- return ty.subst(self, substs.substs);
- }
-
- let ty = self.sess.cstore.closure_ty(self.global_tcx(), def_id);
- self.closure_tys.borrow_mut().insert(def_id, ty.clone());
- ty.subst(self, substs.substs)
+ pub fn closure_type(self, def_id: DefId) -> ty::PolyFnSig<'tcx> {
+ queries::closure_type::get(self, DUMMY_SP, def_id)
}
/// Given the def_id of an impl, return the def_id of the trait it implements.
/// If the given def ID describes a method belonging to an impl, return the
/// ID of the impl that the method belongs to. Otherwise, return `None`.
pub fn impl_of_method(self, def_id: DefId) -> Option<DefId> {
- if def_id.krate != LOCAL_CRATE {
- return self.sess.cstore.associated_item(def_id).and_then(|item| {
- match item.container {
- TraitContainer(_) => None,
- ImplContainer(def_id) => Some(def_id),
- }
- });
- }
- match self.associated_items.borrow().get(&def_id).cloned() {
+ let item = if def_id.krate != LOCAL_CRATE {
+ if let Some(Def::Method(_)) = self.sess.cstore.describe_def(def_id) {
+ Some(self.associated_item(def_id))
+ } else {
+ None
+ }
+ } else {
+ self.maps.associated_item.borrow().get(&def_id).cloned()
+ };
+
+ match item {
Some(trait_item) => {
match trait_item.container {
TraitContainer(_) => None,
if def_id.krate != LOCAL_CRATE {
return self.sess.cstore.trait_of_item(def_id);
}
- match self.associated_items.borrow().get(&def_id) {
+ match self.maps.associated_item.borrow().get(&def_id) {
Some(associated_item) => {
match associated_item.container {
TraitContainer(def_id) => Some(def_id),
Ok(tcx.mk_substs(params)?)
}
-impl<'tcx> Relate<'tcx> for &'tcx ty::BareFnTy<'tcx> {
- fn relate<'a, 'gcx, R>(relation: &mut R,
- a: &&'tcx ty::BareFnTy<'tcx>,
- b: &&'tcx ty::BareFnTy<'tcx>)
- -> RelateResult<'tcx, &'tcx ty::BareFnTy<'tcx>>
- where R: TypeRelation<'a, 'gcx, 'tcx>, 'gcx: 'a+'tcx, 'tcx: 'a
- {
- let unsafety = relation.relate(&a.unsafety, &b.unsafety)?;
- let abi = relation.relate(&a.abi, &b.abi)?;
- let sig = relation.relate(&a.sig, &b.sig)?;
- Ok(relation.tcx().mk_bare_fn(ty::BareFnTy {
- unsafety: unsafety,
- abi: abi,
- sig: sig
- }))
- }
-}
-
impl<'tcx> Relate<'tcx> for ty::FnSig<'tcx> {
fn relate<'a, 'gcx, R>(relation: &mut R,
a: &ty::FnSig<'tcx>,
return Err(TypeError::VariadicMismatch(
expected_found(relation, &a.variadic, &b.variadic)));
}
+ let unsafety = relation.relate(&a.unsafety, &b.unsafety)?;
+ let abi = relation.relate(&a.abi, &b.abi)?;
if a.inputs().len() != b.inputs().len() {
return Err(TypeError::ArgCount);
}).collect::<Result<AccumulateVec<[_; 8]>, _>>()?;
Ok(ty::FnSig {
inputs_and_output: relation.tcx().intern_type_list(&inputs_and_output),
- variadic: a.variadic
+ variadic: a.variadic,
+ unsafety: unsafety,
+ abi: abi
})
}
}
tcx.lift(&self.inputs_and_output).map(|x| {
ty::FnSig {
inputs_and_output: x,
- variadic: self.variadic
- }
- })
- }
-}
-
-impl<'a, 'tcx> Lift<'tcx> for ty::ClosureTy<'a> {
- type Lifted = ty::ClosureTy<'tcx>;
- fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
- tcx.lift(&self.sig).map(|sig| {
- ty::ClosureTy {
- sig: sig,
+ variadic: self.variadic,
unsafety: self.unsafety,
- abi: self.abi
+ abi: self.abi,
}
})
}
}
}
-CopyImpls! { (), hir::Unsafety, abi::Abi, ty::RegionParameterDef }
+CopyImpls! { (), hir::Unsafety, abi::Abi }
impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) {
}
}
-impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::BareFnTy<'tcx> {
- fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- let fty = ty::BareFnTy {
- sig: self.sig.fold_with(folder),
- abi: self.abi,
- unsafety: self.unsafety
- };
- folder.tcx().mk_bare_fn(fty)
- }
-
- fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- folder.fold_bare_fn_ty(self)
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.sig.visit_with(visitor)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::ClosureTy<'tcx> {
- fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- ty::ClosureTy {
- sig: self.sig.fold_with(folder),
- unsafety: self.unsafety,
- abi: self.abi,
- }
- }
-
- fn fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- folder.fold_closure_ty(self)
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.sig.visit_with(visitor)
- }
-}
-
impl<'tcx> TypeFoldable<'tcx> for ty::TypeAndMut<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::TypeAndMut { ty: self.ty.fold_with(folder), mutbl: self.mutbl }
ty::FnSig {
inputs_and_output: folder.tcx().intern_type_list(&inputs_and_output),
variadic: self.variadic,
+ unsafety: self.unsafety,
+ abi: self.abi,
}
}
}
}
-impl<'tcx> TypeFoldable<'tcx> for ty::TypeParameterDef<'tcx> {
- fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- ty::TypeParameterDef {
- name: self.name,
- def_id: self.def_id,
- index: self.index,
- default: self.default.fold_with(folder),
- default_def_id: self.default_def_id,
- pure_wrt_drop: self.pure_wrt_drop,
- }
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.default.visit_with(visitor)
- }
-}
-
-impl<'tcx> TypeFoldable<'tcx> for ty::Generics<'tcx> {
- fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
- ty::Generics {
- parent: self.parent,
- parent_regions: self.parent_regions,
- parent_types: self.parent_types,
- regions: self.regions.fold_with(folder),
- types: self.types.fold_with(folder),
- has_self: self.has_self,
- }
- }
-
- fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
- self.regions.visit_with(visitor) || self.types.visit_with(visitor)
- }
-}
-
impl<'tcx> TypeFoldable<'tcx> for ty::GenericPredicates<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
ty::GenericPredicates {
/// The anonymous type of a function declaration/definition. Each
/// function has a unique type.
- TyFnDef(DefId, &'tcx Substs<'tcx>, &'tcx BareFnTy<'tcx>),
+ TyFnDef(DefId, &'tcx Substs<'tcx>, PolyFnSig<'tcx>),
/// A pointer to a function. Written as `fn() -> i32`.
/// FIXME: This is currently also used to represent the callee of a method;
/// see ty::MethodCallee etc.
- TyFnPtr(&'tcx BareFnTy<'tcx>),
+ TyFnPtr(PolyFnSig<'tcx>),
/// A trait, defined with `trait`.
TyDynamic(Binder<&'tcx Slice<ExistentialPredicate<'tcx>>>, &'tcx ty::Region),
pub substs: &'tcx Substs<'tcx>,
}
+impl<'tcx> TraitRef<'tcx> {
+ pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>) -> TraitRef<'tcx> {
+ TraitRef { def_id: def_id, substs: substs }
+ }
+
+ pub fn self_ty(&self) -> Ty<'tcx> {
+ self.substs.type_at(0)
+ }
+
+ pub fn input_types<'a>(&'a self) -> impl DoubleEndedIterator<Item=Ty<'tcx>> + 'a {
+ // Select only the "input types" from a trait-reference. For
+ // now this is all the types that appear in the
+ // trait-reference, but it should eventually exclude
+ // associated types.
+ self.substs.types()
+ }
+}
+
pub type PolyTraitRef<'tcx> = Binder<TraitRef<'tcx>>;
impl<'tcx> PolyTraitRef<'tcx> {
/// The name `N` of the associated type.
pub item_name: Name,
}
-
-#[derive(Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
-pub struct BareFnTy<'tcx> {
- pub unsafety: hir::Unsafety,
- pub abi: abi::Abi,
- /// Signature (inputs and output) of this function type.
- pub sig: PolyFnSig<'tcx>,
-}
-
-impl<'tcx> serialize::UseSpecializedDecodable for &'tcx BareFnTy<'tcx> {}
-
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
-pub struct ClosureTy<'tcx> {
- pub unsafety: hir::Unsafety,
- pub abi: abi::Abi,
- pub sig: PolyFnSig<'tcx>,
-}
-
/// Signature of a function type, which I have arbitrarily
/// decided to use to refer to the input/output types.
///
/// - `inputs` is the list of arguments and their modes.
/// - `output` is the return type.
/// - `variadic` indicates whether this is a variadic function. (only true for foreign fns)
-#[derive(Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub struct FnSig<'tcx> {
pub inputs_and_output: &'tcx Slice<Ty<'tcx>>,
- pub variadic: bool
+ pub variadic: bool,
+ pub unsafety: hir::Unsafety,
+ pub abi: abi::Abi,
}
impl<'tcx> FnSig<'tcx> {
- pub fn inputs(&self) -> &[Ty<'tcx>] {
+ pub fn inputs(&self) -> &'tcx [Ty<'tcx>] {
&self.inputs_and_output[..self.inputs_and_output.len() - 1]
}
pub type PolyFnSig<'tcx> = Binder<FnSig<'tcx>>;
impl<'tcx> PolyFnSig<'tcx> {
- pub fn inputs(&self) -> Binder<&[Ty<'tcx>]> {
+ pub fn inputs(&self) -> Binder<&'tcx [Ty<'tcx>]> {
Binder(self.skip_binder().inputs())
}
pub fn input(&self, index: usize) -> ty::Binder<Ty<'tcx>> {
pub fn variadic(&self) -> bool {
self.skip_binder().variadic
}
+ pub fn unsafety(&self) -> hir::Unsafety {
+ self.skip_binder().unsafety
+ }
+ pub fn abi(&self) -> abi::Abi {
+ self.skip_binder().abi
+ }
}
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
#[inline]
pub fn is_simd(&self) -> bool {
match self.sty {
- TyAdt(def, _) => def.is_simd(),
+ TyAdt(def, _) => def.repr.simd,
_ => false
}
}
}
}
- pub fn fn_sig(&self) -> &'tcx PolyFnSig<'tcx> {
+ pub fn fn_sig(&self) -> PolyFnSig<'tcx> {
match self.sty {
- TyFnDef(.., ref f) | TyFnPtr(ref f) => &f.sig,
+ TyFnDef(.., f) | TyFnPtr(f) => f,
_ => bug!("Ty::fn_sig() called on non-fn type: {:?}", self)
}
}
- /// Returns the ABI of the given function.
- pub fn fn_abi(&self) -> abi::Abi {
- match self.sty {
- TyFnDef(.., ref f) | TyFnPtr(ref f) => f.abi,
- _ => bug!("Ty::fn_abi() called on non-fn type"),
- }
- }
-
// Type accessors for substructures of types
- pub fn fn_args(&self) -> ty::Binder<&[Ty<'tcx>]> {
+ pub fn fn_args(&self) -> ty::Binder<&'tcx [Ty<'tcx>]> {
self.fn_sig().inputs()
}
mut mk_type: FT)
-> &'tcx Substs<'tcx>
where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
- FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+ FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
let defs = tcx.item_generics(def_id);
let mut substs = Vec::with_capacity(defs.count());
Substs::fill_item(&mut substs, tcx, defs, &mut mk_region, &mut mk_type);
mut mk_type: FT)
-> &'tcx Substs<'tcx>
where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
- FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx>
+ FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx>
{
let defs = tcx.item_generics(def_id);
let mut result = Vec::with_capacity(defs.count());
fn fill_item<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
- defs: &ty::Generics<'tcx>,
+ defs: &ty::Generics,
mk_region: &mut FR,
mk_type: &mut FT)
where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
- FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+ FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
if let Some(def_id) = defs.parent {
let parent_defs = tcx.item_generics(def_id);
}
fn fill_single<FR, FT>(substs: &mut Vec<Kind<'tcx>>,
- defs: &ty::Generics<'tcx>,
+ defs: &ty::Generics,
mk_region: &mut FR,
mk_type: &mut FT)
where FR: FnMut(&ty::RegionParameterDef, &[Kind<'tcx>]) -> &'tcx ty::Region,
- FT: FnMut(&ty::TypeParameterDef<'tcx>, &[Kind<'tcx>]) -> Ty<'tcx> {
+ FT: FnMut(&ty::TypeParameterDef, &[Kind<'tcx>]) -> Ty<'tcx> {
// Handle Self first, before all regions.
let mut types = defs.types.iter();
if defs.parent.is_none() && defs.has_self {
tcx.mk_substs(target_substs.iter().chain(&self[defs.own_count()..]).cloned())
}
- pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics<'tcx>)
+ pub fn truncate_to(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, generics: &ty::Generics)
-> &'tcx Substs<'tcx> {
tcx.mk_substs(self.iter().take(generics.count()).cloned())
}
// except according to those terms.
use dep_graph::DepNode;
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LOCAL_CRATE};
use traits::{self, specialization_graph};
use ty;
use ty::fast_reject;
use hir;
use util::nodemap::FxHashMap;
+use syntax::ast;
+use syntax_pos::DUMMY_SP;
+
/// A trait's definition with type information.
pub struct TraitDef {
pub def_id: DefId,
/// Various flags
pub flags: Cell<TraitFlags>,
+ /// The number of impls we've added from the local crate.
+ /// When this number matches up the list in the HIR map,
+ /// we're done, and the specialization graph is correct.
+ local_impl_count: Cell<usize>,
+
/// The ICH of this trait's DefPath, cached here so it doesn't have to be
/// recomputed all the time.
pub def_path_hash: u64,
nonblanket_impls: RefCell::new(FxHashMap()),
blanket_impls: RefCell::new(vec![]),
flags: Cell::new(ty::TraitFlags::NO_TRAIT_FLAGS),
+ local_impl_count: Cell::new(0),
specialization_graph: RefCell::new(traits::specialization_graph::Graph::new()),
def_path_hash: def_path_hash,
}
assert!(impl_def_id.is_local());
let was_new = self.record_impl(tcx, impl_def_id, impl_trait_ref);
assert!(was_new);
+
+ self.local_impl_count.set(self.local_impl_count.get() + 1);
+ }
+
+ /// Records a trait-to-implementation mapping.
+ pub fn record_has_default_impl(&self) {
+ self.flags.set(self.flags.get() | TraitFlags::HAS_DEFAULT_IMPL);
}
/// Records a trait-to-implementation mapping for a non-local impl.
specialization_graph::ancestors(self, of_impl)
}
+ /// Whether the impl set and specialization graphs are complete.
+ pub fn is_complete(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
+ tcx.populate_implementations_for_trait_if_necessary(self.def_id);
+ ty::queries::coherent_trait::try_get(tcx, DUMMY_SP, (LOCAL_CRATE, self.def_id)).is_ok()
+ }
+
+ /// If any local impls haven't been added yet, returns
+ /// Some(list of local impls for this trait).
+ fn missing_local_impls(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
+ -> Option<&'gcx [ast::NodeId]> {
+ if self.flags.get().intersects(TraitFlags::HAS_LOCAL_IMPLS) {
+ return None;
+ }
+
+ if self.is_complete(tcx) {
+ self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
+ return None;
+ }
+
+ let impls = tcx.hir.trait_impls(self.def_id);
+ assert!(self.local_impl_count.get() <= impls.len());
+ if self.local_impl_count.get() == impls.len() {
+ self.flags.set(self.flags.get() | TraitFlags::HAS_LOCAL_IMPLS);
+ return None;
+ }
+
+ Some(impls)
+ }
+
pub fn for_each_impl<F: FnMut(DefId)>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>, mut f: F) {
self.read_trait_impls(tcx);
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
+ let local_impls = self.missing_local_impls(tcx);
+ if let Some(impls) = local_impls {
+ for &id in impls {
+ f(tcx.hir.local_def_id(id));
+ }
+ }
+ let mut f = |def_id: DefId| {
+ if !(local_impls.is_some() && def_id.is_local()) {
+ f(def_id);
+ }
+ };
+
for &impl_def_id in self.blanket_impls.borrow().iter() {
f(impl_def_id);
}
mut f: F)
{
self.read_trait_impls(tcx);
-
tcx.populate_implementations_for_trait_if_necessary(self.def_id);
+ let local_impls = self.missing_local_impls(tcx);
+ if let Some(impls) = local_impls {
+ for &id in impls {
+ f(tcx.hir.local_def_id(id));
+ }
+ }
+ let mut f = |def_id: DefId| {
+ if !(local_impls.is_some() && def_id.is_local()) {
+ f(def_id);
+ }
+ };
+
for &impl_def_id in self.blanket_impls.borrow().iter() {
f(impl_def_id);
}
const HAS_DEFAULT_IMPL = 1 << 0,
const IS_OBJECT_SAFE = 1 << 1,
const OBJECT_SAFETY_VALID = 1 << 2,
- const IMPLS_VALID = 1 << 3,
+ const HAS_REMOTE_IMPLS = 1 << 3,
+ const HAS_LOCAL_IMPLS = 1 << 4,
}
}
use hir::map as hir_map;
use traits::{self, Reveal};
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
-use ty::{Disr, ParameterEnvironment};
+use ty::{ParameterEnvironment};
use ty::fold::TypeVisitor;
use ty::layout::{Layout, LayoutError};
use ty::TypeVariants::*;
use util::nodemap::FxHashMap;
use middle::lang_items;
+use rustc_const_math::{ConstInt, ConstIsize, ConstUsize};
use rustc_data_structures::stable_hasher::{StableHasher, StableHasherResult};
use std::cell::RefCell;
use hir;
-pub trait IntTypeExt {
- fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
- fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
+type Disr = ConstInt;
+
+ pub trait IntTypeExt {
+ fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>;
+ fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
+ -> Option<Disr>;
+ fn assert_ty_matches(&self, val: Disr);
+ fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr;
+ }
+
+
+macro_rules! typed_literal {
+ ($tcx:expr, $ty:expr, $lit:expr) => {
+ match $ty {
+ SignedInt(ast::IntTy::I8) => ConstInt::I8($lit),
+ SignedInt(ast::IntTy::I16) => ConstInt::I16($lit),
+ SignedInt(ast::IntTy::I32) => ConstInt::I32($lit),
+ SignedInt(ast::IntTy::I64) => ConstInt::I64($lit),
+ SignedInt(ast::IntTy::I128) => ConstInt::I128($lit),
+ SignedInt(ast::IntTy::Is) => match $tcx.sess.target.int_type {
+ ast::IntTy::I16 => ConstInt::Isize(ConstIsize::Is16($lit)),
+ ast::IntTy::I32 => ConstInt::Isize(ConstIsize::Is32($lit)),
+ ast::IntTy::I64 => ConstInt::Isize(ConstIsize::Is64($lit)),
+ _ => bug!(),
+ },
+ UnsignedInt(ast::UintTy::U8) => ConstInt::U8($lit),
+ UnsignedInt(ast::UintTy::U16) => ConstInt::U16($lit),
+ UnsignedInt(ast::UintTy::U32) => ConstInt::U32($lit),
+ UnsignedInt(ast::UintTy::U64) => ConstInt::U64($lit),
+ UnsignedInt(ast::UintTy::U128) => ConstInt::U128($lit),
+ UnsignedInt(ast::UintTy::Us) => match $tcx.sess.target.uint_type {
+ ast::UintTy::U16 => ConstInt::Usize(ConstUsize::Us16($lit)),
+ ast::UintTy::U32 => ConstInt::Usize(ConstUsize::Us32($lit)),
+ ast::UintTy::U64 => ConstInt::Usize(ConstUsize::Us64($lit)),
+ _ => bug!(),
+ },
+ }
+ }
}
impl IntTypeExt for attr::IntType {
- fn to_ty<'a, 'gcx: 'a+'tcx, 'tcx: 'a>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
- match self {
- SignedInt(i) => tcx.mk_mach_int(i),
- UnsignedInt(i) => tcx.mk_mach_uint(i),
+ fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
+ match *self {
+ SignedInt(ast::IntTy::I8) => tcx.types.i8,
+ SignedInt(ast::IntTy::I16) => tcx.types.i16,
+ SignedInt(ast::IntTy::I32) => tcx.types.i32,
+ SignedInt(ast::IntTy::I64) => tcx.types.i64,
+ SignedInt(ast::IntTy::I128) => tcx.types.i128,
+ SignedInt(ast::IntTy::Is) => tcx.types.isize,
+ UnsignedInt(ast::UintTy::U8) => tcx.types.u8,
+ UnsignedInt(ast::UintTy::U16) => tcx.types.u16,
+ UnsignedInt(ast::UintTy::U32) => tcx.types.u32,
+ UnsignedInt(ast::UintTy::U64) => tcx.types.u64,
+ UnsignedInt(ast::UintTy::U128) => tcx.types.u128,
+ UnsignedInt(ast::UintTy::Us) => tcx.types.usize,
}
}
- fn initial_discriminant<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
- 0
+ fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Disr {
+ typed_literal!(tcx, *self, 0)
+ }
+
+ fn assert_ty_matches(&self, val: Disr) {
+ match (*self, val) {
+ (SignedInt(ast::IntTy::I8), ConstInt::I8(_)) => {},
+ (SignedInt(ast::IntTy::I16), ConstInt::I16(_)) => {},
+ (SignedInt(ast::IntTy::I32), ConstInt::I32(_)) => {},
+ (SignedInt(ast::IntTy::I64), ConstInt::I64(_)) => {},
+ (SignedInt(ast::IntTy::I128), ConstInt::I128(_)) => {},
+ (SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) => {},
+ (UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) => {},
+ (UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) => {},
+ (UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) => {},
+ (UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) => {},
+ (UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) => {},
+ (UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) => {},
+ _ => bug!("disr type mismatch: {:?} vs {:?}", self, val),
+ }
+ }
+
+ fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Disr>)
+ -> Option<Disr> {
+ if let Some(val) = val {
+ self.assert_ty_matches(val);
+ (val + typed_literal!(tcx, *self, 1)).ok()
+ } else {
+ Some(self.initial_discriminant(tcx))
+ }
}
}
self_type: Ty<'tcx>, span: Span)
-> Result<(), CopyImplementationError> {
// FIXME: (@jroesch) float this code up
- tcx.infer_ctxt(self.clone(), Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt(self.clone(), Reveal::UserFacing).enter(|infcx| {
let (adt, substs) = match self_type.sty {
ty::TyAdt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt)
}
}
- if adt.has_dtor() {
+ if adt.has_dtor(tcx) {
return Err(CopyImplementationError::HasDestructor);
}
}
}
- /// Returns the IntType representation.
- /// This used to ensure `int_ty` doesn't contain `usize` and `isize`
- /// by converting them to their actual types. That doesn't happen anymore.
- pub fn enum_repr_type(self, opt_hint: Option<&attr::ReprAttr>) -> attr::IntType {
- match opt_hint {
- // Feed in the given type
- Some(&attr::ReprInt(int_t)) => int_t,
- // ... but provide sensible default if none provided
- //
- // NB. Historically `fn enum_variants` generate i64 here, while
- // rustc_typeck::check would generate isize.
- _ => SignedInt(ast::IntTy::Is),
- }
- }
-
/// Returns the deeply last field of nested structures, or the same type,
/// if not a structure at all. Corresponds to the only possible unsized
/// field, and its type can be used to determine unsizing strategy.
/// (This allows programs to make cyclic structures without
/// resorting to unasfe means; see RFCs 769 and 1238).
pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
- let dtor_method = match adt.destructor() {
+ let dtor_method = match adt.destructor(self) {
Some(dtor) => dtor,
None => return false
};
TyFnDef(def_id, ..) => self.def_id(def_id),
TyAdt(d, _) => self.def_id(d.did),
TyFnPtr(f) => {
- self.hash(f.unsafety);
- self.hash(f.abi);
- self.hash(f.sig.variadic());
- self.hash(f.sig.skip_binder().inputs().len());
+ self.hash(f.unsafety());
+ self.hash(f.abi());
+ self.hash(f.variadic());
+ self.hash(f.inputs().skip_binder().len());
}
TyDynamic(ref data, ..) => {
if let Some(p) = data.principal() {
}
}
let result =
- tcx.infer_ctxt(param_env.clone(), Reveal::ExactMatch)
+ tcx.infer_ctxt(param_env.clone(), Reveal::UserFacing)
.enter(|infcx| {
traits::type_known_to_meet_bound(&infcx, self, def_id, span)
});
ty::TyTuple(ts, _) => {
stack.extend(ts.iter().cloned().rev());
}
- ty::TyFnDef(_, substs, ref ft) => {
+ ty::TyFnDef(_, substs, ft) => {
stack.extend(substs.types().rev());
- push_sig_subtypes(stack, &ft.sig);
+ push_sig_subtypes(stack, ft);
}
- ty::TyFnPtr(ref ft) => {
- push_sig_subtypes(stack, &ft.sig);
+ ty::TyFnPtr(ft) => {
+ push_sig_subtypes(stack, ft);
}
}
}
-fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: &ty::PolyFnSig<'tcx>) {
+fn push_sig_subtypes<'tcx>(stack: &mut TypeWalkerStack<'tcx>, sig: ty::PolyFnSig<'tcx>) {
stack.push(sig.skip_binder().output());
stack.extend(sig.skip_binder().inputs().iter().cloned().rev());
}
}
if !verbose {
- if generics.types.last().map_or(false, |def| def.default.is_some()) {
+ if generics.types.last().map_or(false, |def| def.has_default) {
if let Some(substs) = tcx.lift(&substs) {
let tps = substs.types().rev().skip(child_types);
for (def, actual) in generics.types.iter().rev().zip(tps) {
- if def.default.subst(tcx, substs) != Some(actual) {
+ if !def.has_default {
+ break;
+ }
+ if tcx.item_type(def.def_id).subst(tcx, substs) != actual {
break;
}
num_supplied_defaults += 1;
}
}
-impl<'tcx> fmt::Debug for ty::TypeParameterDef<'tcx> {
+impl fmt::Debug for ty::TypeParameterDef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "TypeParameterDef({}, {:?}, {})",
self.name,
}
}
-impl<'tcx> fmt::Debug for ty::ClosureTy<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "ClosureTy({},{:?},{})",
- self.unsafety,
- self.sig,
- self.abi)
- }
-}
-
impl<'tcx> fmt::Debug for ty::ClosureUpvar<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "ClosureUpvar({:?},{:?})",
impl<'tcx> fmt::Display for ty::FnSig<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if self.unsafety == hir::Unsafety::Unsafe {
+ write!(f, "unsafe ")?;
+ }
+
+ if self.abi != Abi::Rust {
+ write!(f, "extern {} ", self.abi)?;
+ }
+
write!(f, "fn")?;
fn_sig(f, self.inputs(), self.variadic, self.output())
}
write!(f, ")")
}
TyFnDef(def_id, substs, ref bare_fn) => {
- if bare_fn.unsafety == hir::Unsafety::Unsafe {
- write!(f, "unsafe ")?;
- }
-
- if bare_fn.abi != Abi::Rust {
- write!(f, "extern {} ", bare_fn.abi)?;
- }
-
- write!(f, "{} {{", bare_fn.sig.0)?;
+ write!(f, "{} {{", bare_fn.0)?;
parameterized(f, substs, def_id, &[])?;
write!(f, "}}")
}
TyFnPtr(ref bare_fn) => {
- if bare_fn.unsafety == hir::Unsafety::Unsafe {
- write!(f, "unsafe ")?;
- }
-
- if bare_fn.abi != Abi::Rust {
- write!(f, "extern {} ", bare_fn.abi)?;
- }
-
- write!(f, "{}", bare_fn.sig.0)
+ write!(f, "{}", bare_fn.0)
}
TyInfer(infer_ty) => write!(f, "{}", infer_ty),
TyError => write!(f, "[type error]"),
TyParam(ref param_ty) => write!(f, "{}", param_ty),
- TyAdt(def, substs) => {
- ty::tls::with(|tcx| {
- if def.did.is_local() &&
- !tcx.item_types.borrow().contains_key(&def.did) {
- write!(f, "{}<..>", tcx.item_path_str(def.did))
- } else {
- parameterized(f, substs, def.did, &[])
- }
- })
- }
+ TyAdt(def, substs) => parameterized(f, substs, def.did, &[]),
TyDynamic(data, r) => {
write!(f, "{}", data)?;
let r = r.to_string();
("armv7s-apple-ios", armv7s_apple_ios),
("x86_64-sun-solaris", x86_64_sun_solaris),
+ ("sparcv9-sun-solaris", sparcv9_sun_solaris),
("x86_64-pc-windows-gnu", x86_64_pc_windows_gnu),
("i686-pc-windows-gnu", i686_pc_windows_gnu),
--- /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.
+
+use target::{Target, TargetResult};
+
+pub fn target() -> TargetResult {
+ let mut base = super::solaris_base::opts();
+ base.pre_link_args.push("-m64".to_string());
+ // llvm calls this "v9"
+ base.cpu = "v9".to_string();
+ base.max_atomic_width = Some(64);
+
+ Ok(Target {
+ llvm_target: "sparcv9-sun-solaris".to_string(),
+ target_endian: "big".to_string(),
+ target_pointer_width: "64".to_string(),
+ data_layout: "E-m:e-i64:64-n32:64-S128".to_string(),
+ // Use "sparc64" instead of "sparcv9" here, since the former is already
+ // used widely in the source base. If we ever needed ABI
+ // differentiation from the sparc64, we could, but that would probably
+ // just be confusing.
+ arch: "sparc64".to_string(),
+ target_os: "solaris".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "sun".to_string(),
+ options: base,
+ })
+}
}
LpExtend(ref lp_base, _, LpInterior(_, InteriorField(_))) => {
match lp_base.to_type().sty {
- ty::TyAdt(def, _) if def.has_dtor() => {
+ ty::TyAdt(def, _) if def.has_dtor(self.tcx()) => {
// In the case where the owner implements drop, then
// the path must be initialized to prevent a case of
// partial reinitialization
Categorization::Interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
match b.ty.sty {
ty::TyAdt(def, _) => {
- if def.has_dtor() {
+ if def.has_dtor(bccx.tcx) {
Some(cmt.clone())
} else {
check_and_get_illegal_move_origin(bccx, b)
Categorization::Downcast(ref b, _) |
Categorization::Interior(ref b, mc::InteriorField(_)) => {
match b.ty.sty {
- ty::TyAdt(def, _) if def.has_dtor() => {
+ ty::TyAdt(def, _) if def.has_dtor(bccx.tcx) => {
let mut err = struct_span_err!(bccx, move_from.span, E0509,
"cannot move out of type `{}`, \
which implements the `Drop` trait",
{
if let mir::Operand::Constant(ref func) = *oper
{
- if let ty::TyFnDef(def_id, _, &ty::BareFnTy { abi, .. }) = func.ty.sty
+ if let ty::TyFnDef(def_id, _, sig) = func.ty.sty
{
+ let abi = sig.abi();
let name = tcx.item_name(def_id);
if abi == Abi::RustIntrinsic || abi == Abi::PlatformIntrinsic {
if name == "rustc_peek" {
use rustc::ty::util::IntTypeExt;
use rustc::mir::*;
use rustc::mir::transform::{Pass, MirPass, MirSource};
-use rustc::middle::const_val::{ConstVal, ConstInt};
+use rustc::middle::const_val::ConstVal;
use rustc::middle::lang_items;
use rustc::util::nodemap::FxHashMap;
use rustc_data_structures::indexed_set::IdxSetBuf;
let mut values = Vec::with_capacity(adt.variants.len());
let mut blocks = Vec::with_capacity(adt.variants.len());
let mut otherwise = None;
- for (variant_index, variant) in adt.variants.iter().enumerate() {
- let discr = ConstInt::new_inttype(variant.disr_val, adt.discr_ty,
- self.tcx.sess.target.uint_type,
- self.tcx.sess.target.int_type).unwrap();
+ for (variant_index, discr) in adt.discriminants(self.tcx).enumerate() {
let subpath = super::move_path_children_matching(
self.move_data(), c.path, |proj| match proj {
&Projection {
// Additionally, we do not want to switch on the
// discriminant after it is free-ed, because that
// way lies only trouble.
- let discr_ty = adt.discr_ty.to_ty(self.tcx);
+ let discr_ty = adt.repr.discr_type().to_ty(self.tcx);
let discr = Lvalue::Local(self.patch.new_temp(discr_ty));
let switch_block = self.patch.new_block(BasicBlockData {
statements: vec![
match ty.sty {
ty::TyAdt(def, _) => {
- if def.has_dtor() && !def.is_box() {
+ if def.has_dtor(self.tcx) && !def.is_box() {
self.tcx.sess.span_warn(
c.source_info.span,
&format!("dataflow bug??? moving out of type with dtor {:?}",
// error: can't move out of borrowed content
ty::TyRef(..) | ty::TyRawPtr(..) => return Err(MovePathError::IllegalMove),
// error: can't move out of struct with destructor
- ty::TyAdt(adt, _) if adt.has_dtor() && !adt.is_box() =>
+ ty::TyAdt(adt, _) if adt.has_dtor(self.tcx) && !adt.is_box() =>
return Err(MovePathError::IllegalMove),
// move out of union - always move the entire union
ty::TyAdt(adt, _) if adt.is_union() =>
lv, ty);
true
}
- ty::TyAdt(def, _) if (def.has_dtor() && !def.is_box()) || def.is_union() => {
+ ty::TyAdt(def, _) if (def.has_dtor(tcx) && !def.is_box()) || def.is_union() => {
debug!("lvalue_contents_drop_state_cannot_differ lv: {:?} ty: {:?} Drop => true",
lv, ty);
true
}
}).clone()
}
+
+ fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
+ if self.tcx.sess.features.borrow().never_type {
+ ty.is_uninhabited_from(self.module, self.tcx)
+ } else {
+ false
+ }
+ }
+
+ fn is_variant_uninhabited(&self,
+ variant: &'tcx ty::VariantDef,
+ 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)
+ } else {
+ false
+ }
+ }
}
#[derive(Clone, Debug, PartialEq)]
-pub enum Constructor {
+pub enum Constructor<'tcx> {
/// The constructor of all patterns that don't vary by constructor,
/// e.g. struct patterns and fixed-length arrays.
Single,
/// Enum variants.
Variant(DefId),
/// Literal values.
- ConstantValue(ConstVal),
+ ConstantValue(ConstVal<'tcx>),
/// Ranges of literal values (`2...5` and `2..5`).
- ConstantRange(ConstVal, ConstVal, RangeEnd),
+ ConstantRange(ConstVal<'tcx>, ConstVal<'tcx>, RangeEnd),
/// Array patterns of length n.
Slice(usize),
}
-impl<'tcx> Constructor {
+impl<'tcx> Constructor<'tcx> {
fn variant_index_for_adt(&self, adt: &'tcx ty::AdtDef) -> usize {
match self {
&Variant(vid) => adt.variant_index_with_id(vid),
fn push_wild_constructor<'a>(
mut self,
cx: &MatchCheckCtxt<'a, 'tcx>,
- ctor: &Constructor,
+ ctor: &Constructor<'tcx>,
ty: Ty<'tcx>)
-> Self
{
fn apply_constructor<'a>(
mut self,
cx: &MatchCheckCtxt<'a,'tcx>,
- ctor: &Constructor,
+ ctor: &Constructor<'tcx>,
ty: Ty<'tcx>)
-> Self
{
/// We make sure to omit constructors that are statically impossible. eg for
/// Option<!> we do not include Some(_) in the returned list of constructors.
fn all_constructors<'a, 'tcx: 'a>(cx: &mut MatchCheckCtxt<'a, 'tcx>,
- pcx: PatternContext<'tcx>) -> Vec<Constructor>
+ pcx: PatternContext<'tcx>)
+ -> Vec<Constructor<'tcx>>
{
- let check_inhabited = cx.tcx.sess.features.borrow().never_type;
debug!("all_constructors({:?})", pcx.ty);
match pcx.ty.sty {
ty::TyBool =>
[true, false].iter().map(|b| ConstantValue(ConstVal::Bool(*b))).collect(),
ty::TySlice(ref sub_ty) => {
- if sub_ty.is_uninhabited_from(cx.module, cx.tcx)
- && check_inhabited
- {
+ if cx.is_uninhabited(sub_ty) {
vec![Slice(0)]
} else {
(0..pcx.max_slice_length+1).map(|length| Slice(length)).collect()
}
}
ty::TyArray(ref sub_ty, length) => {
- if length == 0 || !(sub_ty.is_uninhabited_from(cx.module, cx.tcx)
- && check_inhabited)
- {
- vec![Slice(length)]
- } else {
+ if length > 0 && cx.is_uninhabited(sub_ty) {
vec![]
+ } else {
+ vec![Slice(length)]
}
}
ty::TyAdt(def, substs) if def.is_enum() && def.variants.len() != 1 => {
- def.variants.iter().filter_map(|v| {
- let mut visited = FxHashMap::default();
- let forest = v.uninhabited_from(&mut visited,
- cx.tcx, substs,
- AdtKind::Enum);
- if forest.contains(cx.tcx, cx.module)
- && check_inhabited
- {
- None
- } else {
- Some(Variant(v.did))
- }
- }).collect()
+ def.variants.iter()
+ .filter(|v| !cx.is_variant_uninhabited(v, substs))
+ .map(|v| Variant(v.did))
+ .collect()
}
_ => {
- if pcx.ty.is_uninhabited_from(cx.module, cx.tcx)
- && check_inhabited
- {
+ if cx.is_uninhabited(pcx.ty) {
vec![]
} else {
vec![Single]
assert!(rows.iter().all(|r| r.len() == v.len()));
-
let pcx = PatternContext {
ty: rows.iter().map(|r| r[0].ty).find(|ty| !ty.references_error())
.unwrap_or(v[0].ty),
let missing_ctors: Vec<Constructor> = all_ctors.iter().filter(|c| {
!used_ctors.contains(*c)
}).cloned().collect();
- debug!("missing_ctors = {:?}", missing_ctors);
// `missing_ctors` is the set of constructors from the same type as the
// first column of `matrix` that are matched only by wildcard patterns
// Therefore, if there is some pattern that is unmatched by `matrix`,
// it will still be unmatched if the first constructor is replaced by
// any of the constructors in `missing_ctors`
-
- if missing_ctors.is_empty() {
+ //
+ // However, if our scrutinee is *privately* an empty enum, we
+ // must treat it as though it had an "unknown" constructor (in
+ // that case, all other patterns obviously can't be variants)
+ // to avoid exposing its emptyness. See the `match_privately_empty`
+ // test for details.
+ //
+ // FIXME: currently the only way I know of something can
+ // be a privately-empty enum is when the never_type
+ // feature flag is not present, so this is only
+ // needed for that case.
+
+ let is_privately_empty =
+ all_ctors.is_empty() && !cx.is_uninhabited(pcx.ty);
+ debug!("missing_ctors={:?} is_privately_empty={:?}", missing_ctors,
+ is_privately_empty);
+ if missing_ctors.is_empty() && !is_privately_empty {
all_ctors.into_iter().map(|c| {
is_useful_specialized(cx, matrix, v, c.clone(), pcx.ty, witness)
}).find(|result| result.is_useful()).unwrap_or(NotUseful)
cx: &mut MatchCheckCtxt<'a, 'tcx>,
&Matrix(ref m): &Matrix<'p, 'tcx>,
v: &[&'p Pattern<'tcx>],
- ctor: Constructor,
+ ctor: Constructor<'tcx>,
lty: Ty<'tcx>,
witness: WitnessPreference) -> Usefulness<'tcx>
{
+ debug!("is_useful_specialized({:?}, {:?}, {:?})", v, ctor, lty);
let sub_pat_tys = constructor_sub_pattern_tys(cx, &ctor, lty);
let wild_patterns_owned: Vec<_> = sub_pat_tys.iter().map(|ty| {
Pattern {
/// `[a, b, ..tail]` can match a slice of length 2, 3, 4 and so on.
///
/// Returns None in case of a catch-all, which can't be specialized.
-fn pat_constructors(_cx: &mut MatchCheckCtxt,
- pat: &Pattern,
- pcx: PatternContext)
- -> Option<Vec<Constructor>>
+fn pat_constructors<'tcx>(_cx: &mut MatchCheckCtxt,
+ pat: &Pattern<'tcx>,
+ pcx: PatternContext)
+ -> Option<Vec<Constructor<'tcx>>>
{
match *pat.kind {
PatternKind::Binding { .. } | PatternKind::Wild =>
ty::TyRef(_, ref ty_and_mut) => vec![ty_and_mut.ty],
ty::TyAdt(adt, substs) => {
adt.variants[ctor.variant_index_for_adt(adt)].fields.iter().map(|field| {
- field.ty(cx.tcx, substs)
+ let is_visible = adt.is_enum()
+ || field.vis.is_accessible_from(cx.module, cx.tcx);
+ if is_visible {
+ field.ty(cx.tcx, substs)
+ } else {
+ // Treat all non-visible fields as nil. They
+ // can't appear in any other pattern from
+ // this match (because they are private),
+ // so their type does not matter - but
+ // we don't want to know they are
+ // uninhabited.
+ cx.tcx.mk_nil()
+ }
}).collect()
}
_ => vec![],
"statics cannot be referenced in patterns");
}
PatternError::ConstEval(err) => {
- report_const_eval_err(self.tcx, &err, pat_span, "pattern").emit();
+ report_const_eval_err(self.tcx, &err, pat_span, "pattern");
}
}
}
// Fourth, check for unreachable arms.
check_arms(cx, &inlined_arms, source);
+ // Then, if the match has no arms, check whether the scrutinee
+ // is uninhabited.
+ let pat_ty = self.tables.node_id_to_type(scrut.id);
+ let module = self.tcx.hir.local_def_id(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)
+ } else {
+ self.conservative_is_uninhabited(pat_ty)
+ };
+ if !scrutinee_is_uninhabited {
+ // We know the type is inhabited, so this must be wrong
+ let mut err = create_e0004(self.tcx.sess, scrut.span,
+ format!("non-exhaustive patterns: type {} \
+ is non-empty",
+ pat_ty));
+ span_help!(&mut err, scrut.span,
+ "Please ensure that all possible cases are being handled; \
+ possibly adding wildcards or more match arms.");
+ err.emit();
+ }
+ // If the type *is* uninhabited, it's vacuously exhaustive
+ return;
+ }
+
let matrix: Matrix = inlined_arms
.iter()
.filter(|&&(_, guard)| guard.is_none())
})
}
+ fn conservative_is_uninhabited(&self, scrutinee_ty: Ty<'tcx>) -> bool {
+ // "rustc-1.0-style" uncontentious uninhabitableness check
+ match scrutinee_ty.sty {
+ ty::TyNever => true,
+ ty::TyAdt(def, _) => def.variants.is_empty(),
+ _ => false
+ }
+ }
+
fn check_irrefutable(&self, pat: &Pat, is_fn_arg: bool) {
let origin = if is_fn_arg {
"function argument"
///
/// FIXME: this should be done by borrowck.
fn check_for_mutation_in_guard(cx: &MatchVisitor, guard: &hir::Expr) {
- cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::NotSpecializable).enter(|infcx| {
+ cx.tcx.infer_ctxt((cx.tables, cx.param_env.clone()), Reveal::UserFacing).enter(|infcx| {
let mut checker = MutationChecker {
cx: cx,
};
https://doc.rust-lang.org/reference.html#ffi-attributes
"##,
-
-E0306: r##"
-In an array type `[T; N]`, `N` is the number of elements in the array. This
-must be an unsigned integer. Erroneous code example:
-
-```compile_fail,E0306
-const X: [i32; true] = [0]; // error: expected `usize` for array length,
- // found boolean
-```
-
-Working example:
-
-```
-const X: [i32; 1] = [0];
-```
-"##,
}
use rustc::middle::const_val::ConstVal::*;
use rustc::middle::const_val::ConstVal;
use self::ErrKind::*;
-use self::EvalHint::*;
use rustc::hir::map as hir_map;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::util::IntTypeExt;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, Subst};
use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
use rustc::util::nodemap::DefIdMap;
use graphviz::IntoCow;
use syntax::ast;
use rustc::hir::{self, Expr};
-use syntax::attr::IntType;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
use std::borrow::Cow;
use std::cmp::Ordering;
use rustc_const_math::*;
use rustc_errors::DiagnosticBuilder;
+macro_rules! signal {
+ ($e:expr, $exn:expr) => {
+ return Err(ConstEvalErr { span: $e.span, kind: $exn })
+ }
+}
+
macro_rules! math {
($e:expr, $op:expr) => {
match $op {
Ok(val) => val,
- Err(e) => signal!($e, Math(e)),
+ Err(e) => signal!($e, ErrKind::from(e)),
}
}
}
fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
variant_def: DefId)
- -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>)> {
+ -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)> {
if let Some(variant_node_id) = tcx.hir.as_local_node_id(variant_def) {
let enum_node_id = tcx.hir.get_parent(variant_node_id);
if let Some(hir_map::NodeItem(it)) = tcx.hir.find(enum_node_id) {
return variant.node.disr_expr.map(|e| {
let def_id = tcx.hir.body_owner_def_id(e);
(&tcx.hir.body(e).value,
- tcx.tables.borrow().get(&def_id).cloned())
+ tcx.item_tables(def_id))
});
}
}
/// This generally happens in late/trans const evaluation.
pub fn lookup_const_by_id<'a, 'tcx: 'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
- substs: Option<&'tcx Substs<'tcx>>)
+ substs: &'tcx Substs<'tcx>)
-> Option<(&'tcx Expr,
- Option<&'a ty::TypeckTables<'tcx>>,
- Option<ty::Ty<'tcx>>)> {
+ &'a ty::TypeckTables<'tcx>)> {
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
match tcx.hir.find(node_id) {
None => None,
Some(hir_map::NodeItem(&hir::Item {
- node: hir::ItemConst(ref ty, body), ..
+ node: hir::ItemConst(_, body), ..
})) |
Some(hir_map::NodeImplItem(&hir::ImplItem {
- node: hir::ImplItemKind::Const(ref ty, body), ..
+ node: hir::ImplItemKind::Const(_, body), ..
})) => {
Some((&tcx.hir.body(body).value,
- tcx.tables.borrow().get(&def_id).cloned(),
- tcx.ast_ty_to_prim_ty(ty)))
+ tcx.item_tables(def_id)))
}
Some(hir_map::NodeTraitItem(ti)) => match ti.node {
- hir::TraitItemKind::Const(ref ty, default) => {
- if let Some(substs) = substs {
- // If we have a trait item and the substitutions for it,
- // `resolve_trait_associated_const` will select an impl
- // or the default.
- let trait_id = tcx.hir.get_parent(node_id);
- let trait_id = tcx.hir.local_def_id(trait_id);
- let default_value = default.map(|body| {
- (&tcx.hir.body(body).value,
- tcx.tables.borrow().get(&def_id).cloned(),
- tcx.ast_ty_to_prim_ty(ty))
- });
- resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
- } else {
- // Technically, without knowing anything about the
- // expression that generates the obligation, we could
- // still return the default if there is one. However,
- // it's safer to return `None` than to return some value
- // that may differ from what you would get from
- // correctly selecting an impl.
- None
- }
+ hir::TraitItemKind::Const(_, default) => {
+ // If we have a trait item and the substitutions for it,
+ // `resolve_trait_associated_const` will select an impl
+ // or the default.
+ let trait_id = tcx.hir.get_parent(node_id);
+ let trait_id = tcx.hir.local_def_id(trait_id);
+ let default_value = default.map(|body| {
+ (&tcx.hir.body(body).value,
+ tcx.item_tables(def_id))
+ });
+ resolve_trait_associated_const(tcx, def_id, default_value, trait_id, substs)
}
_ => None
},
Some(_) => None
}
} else {
- let expr_tables_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
- (&body.value, Some(tcx.item_tables(def_id)),
- Some(tcx.sess.cstore.item_type(tcx, def_id)))
+ let expr_and_tables = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
+ (&body.value, tcx.item_tables(def_id))
});
match tcx.sess.cstore.describe_def(def_id) {
Some(Def::AssociatedConst(_)) => {
// trait-associated const if the caller gives us the
// substitutions for the reference to it.
if let Some(trait_id) = trait_id {
- if let Some(substs) = substs {
- resolve_trait_associated_const(tcx, def_id, expr_tables_ty,
- trait_id, substs)
- } else {
- None
- }
+ resolve_trait_associated_const(tcx, def_id, expr_and_tables,
+ trait_id, substs)
} else {
- expr_tables_ty
+ expr_and_tables
}
},
- Some(Def::Const(..)) => expr_tables_ty,
+ Some(Def::Const(..)) => expr_and_tables,
_ => None
}
}
}
fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
- -> Option<(&'tcx hir::Body, Option<&'a ty::TypeckTables<'tcx>>)>
+ -> Option<(&'tcx hir::Body, &'a ty::TypeckTables<'tcx>)>
{
if let Some(node_id) = tcx.hir.as_local_node_id(def_id) {
FnLikeNode::from_node(tcx.hir.get(node_id)).and_then(|fn_like| {
if fn_like.constness() == hir::Constness::Const {
Some((tcx.hir.body(fn_like.body()),
- tcx.tables.borrow().get(&def_id).cloned()))
+ tcx.item_tables(def_id)))
} else {
None
}
} else {
if tcx.sess.cstore.is_const_fn(def_id) {
tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
- (body, Some(tcx.item_tables(def_id)))
+ (body, tcx.item_tables(def_id))
})
} else {
None
}
}
-pub fn report_const_eval_err<'a, 'tcx>(
+fn build_const_eval_err<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
err: &ConstEvalErr,
primary_span: Span,
diag
}
+pub fn report_const_eval_err<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ err: &ConstEvalErr,
+ primary_span: Span,
+ primary_kind: &str)
+{
+ if let TypeckError = err.kind {
+ return;
+ }
+ build_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+}
+
pub fn fatal_const_eval_err<'a, 'tcx>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
err: &ConstEvalErr,
primary_kind: &str)
-> !
{
- report_const_eval_err(tcx, err, primary_span, primary_kind).emit();
+ report_const_eval_err(tcx, err, primary_span, primary_kind);
tcx.sess.abort_if_errors();
unreachable!()
}
pub struct ConstContext<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- tables: Option<&'a ty::TypeckTables<'tcx>>,
- fn_args: Option<DefIdMap<ConstVal>>
+ tables: &'a ty::TypeckTables<'tcx>,
+ substs: &'tcx Substs<'tcx>,
+ fn_args: Option<DefIdMap<ConstVal<'tcx>>>
}
impl<'a, 'tcx> ConstContext<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, body: hir::BodyId) -> Self {
let def_id = tcx.hir.body_owner_def_id(body);
- ConstContext {
- tcx: tcx,
- tables: tcx.tables.borrow().get(&def_id).cloned(),
- fn_args: None
- }
+ ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
+ ConstContext::with_tables(tcx, tcx.item_tables(def_id))
}
pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
ConstContext {
tcx: tcx,
- tables: Some(tables),
+ tables: tables,
+ substs: tcx.intern_substs(&[]),
fn_args: None
}
}
/// Evaluate a constant expression in a context where the expression isn't
- /// guaranteed to be evaluatable. `ty_hint` is usually ExprTypeChecked,
- /// but a few places need to evaluate constants during type-checking, like
- /// computing the length of an array. (See also the FIXME above EvalHint.)
- pub fn eval(&self, e: &Expr, ty_hint: EvalHint<'tcx>) -> EvalResult {
- eval_const_expr_partial(self, e, ty_hint)
+ /// guaranteed to be evaluatable.
+ pub fn eval(&self, e: &Expr) -> EvalResult<'tcx> {
+ if self.tables.tainted_by_errors {
+ signal!(e, TypeckError);
+ }
+ eval_const_expr_partial(self, e)
}
}
#[derive(Clone, Debug)]
-pub struct ConstEvalErr {
+pub struct ConstEvalErr<'tcx> {
pub span: Span,
- pub kind: ErrKind,
+ pub kind: ErrKind<'tcx>,
}
#[derive(Clone, Debug)]
-pub enum ErrKind {
+pub enum ErrKind<'tcx> {
CannotCast,
- CannotCastTo(&'static str),
- InvalidOpForInts(hir::BinOp_),
- InvalidOpForBools(hir::BinOp_),
- InvalidOpForFloats(hir::BinOp_),
- InvalidOpForIntUint(hir::BinOp_),
- InvalidOpForUintInt(hir::BinOp_),
- NegateOn(ConstVal),
- NotOn(ConstVal),
- CallOn(ConstVal),
-
MissingStructField,
+ NegateOn(ConstVal<'tcx>),
+ NotOn(ConstVal<'tcx>),
+ CallOn(ConstVal<'tcx>),
+
NonConstPath,
UnimplementedConstVal(&'static str),
- UnresolvedPath,
ExpectedConstTuple,
ExpectedConstStruct,
- TupleIndexOutOfBounds,
IndexedNonVec,
- IndexNegative,
- IndexNotInt,
+ IndexNotUsize,
IndexOutOfBounds { len: u64, index: u64 },
- RepeatCountNotNatural,
- RepeatCountNotInt,
MiscBinaryOp,
MiscCatchAll,
IndexOpFeatureGated,
Math(ConstMathErr),
- IntermediateUnsignedNegative,
- /// Expected, Got
- TypeMismatch(String, ConstInt),
+ ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
- BadType(ConstVal),
- ErroneousReferencedConstant(Box<ConstEvalErr>),
- CharCast(ConstInt),
+ TypeckError
}
-impl From<ConstMathErr> for ErrKind {
- fn from(err: ConstMathErr) -> ErrKind {
- Math(err)
+impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
+ fn from(err: ConstMathErr) -> ErrKind<'tcx> {
+ match err {
+ ConstMathErr::UnsignedNegation => TypeckError,
+ _ => Math(err)
+ }
}
}
}
}
-impl ConstEvalErr {
+impl<'tcx> ConstEvalErr<'tcx> {
pub fn description(&self) -> ConstEvalErrDescription {
use self::ErrKind::*;
use self::ConstEvalErrDescription::*;
match self.kind {
CannotCast => simple!("can't cast this type"),
- CannotCastTo(s) => simple!("can't cast this type to {}", s),
- InvalidOpForInts(_) => simple!("can't do this op on integrals"),
- InvalidOpForBools(_) => simple!("can't do this op on bools"),
- InvalidOpForFloats(_) => simple!("can't do this op on floats"),
- InvalidOpForIntUint(..) => simple!("can't do this op on an isize and usize"),
- InvalidOpForUintInt(..) => simple!("can't do this op on a usize and isize"),
NegateOn(ref const_val) => simple!("negate on {}", const_val.description()),
NotOn(ref const_val) => simple!("not on {}", const_val.description()),
CallOn(ref const_val) => simple!("call on {}", const_val.description()),
NonConstPath => simple!("non-constant path in constant expression"),
UnimplementedConstVal(what) =>
simple!("unimplemented constant expression: {}", what),
- UnresolvedPath => simple!("unresolved path in constant expression"),
ExpectedConstTuple => simple!("expected constant tuple"),
ExpectedConstStruct => simple!("expected constant struct"),
- TupleIndexOutOfBounds => simple!("tuple index out of bounds"),
IndexedNonVec => simple!("indexing is only supported for arrays"),
- IndexNegative => simple!("indices must be non-negative integers"),
- IndexNotInt => simple!("indices must be integers"),
+ IndexNotUsize => simple!("indices must be of type `usize`"),
IndexOutOfBounds { len, index } => {
simple!("index out of bounds: the len is {} but the index is {}",
len, index)
}
- RepeatCountNotNatural => simple!("repeat count must be a natural number"),
- RepeatCountNotInt => simple!("repeat count must be integers"),
MiscBinaryOp => simple!("bad operands for binary"),
MiscCatchAll => simple!("unsupported constant expr"),
IndexOpFeatureGated => simple!("the index operation on const values is unstable"),
Math(ref err) => Simple(err.description().into_cow()),
- IntermediateUnsignedNegative => simple!(
- "during the computation of an unsigned a negative \
- number was encountered. This is most likely a bug in\
- the constant evaluator"),
-
- TypeMismatch(ref expected, ref got) => {
- simple!("expected {}, found {}", expected, got.description())
- },
- BadType(ref i) => simple!("value of wrong type: {:?}", i),
ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
- CharCast(ref got) => {
- simple!("only `u8` can be cast as `char`, not `{}`", got.description())
- },
- }
- }
-}
-
-pub type EvalResult = Result<ConstVal, ConstEvalErr>;
-pub type CastResult = Result<ConstVal, ErrKind>;
-
-// FIXME: Long-term, this enum should go away: trying to evaluate
-// an expression which hasn't been type-checked is a recipe for
-// disaster. That said, it's not clear how to fix ast_ty_to_ty
-// to avoid the ordering issue.
-
-/// Hint to determine how to evaluate constant expressions which
-/// might not be type-checked.
-#[derive(Copy, Clone, Debug)]
-pub enum EvalHint<'tcx> {
- /// We have a type-checked expression.
- ExprTypeChecked,
- /// We have an expression which hasn't been type-checked, but we have
- /// an idea of what the type will be because of the context. For example,
- /// the length of an array is always `usize`. (This is referred to as
- /// a hint because it isn't guaranteed to be consistent with what
- /// type-checking would compute.)
- UncheckedExprHint(Ty<'tcx>),
- /// We have an expression which has not yet been type-checked, and
- /// and we have no clue what the type will be.
- UncheckedExprNoHint,
-}
-impl<'tcx> EvalHint<'tcx> {
- fn erase_hint(&self) -> EvalHint<'tcx> {
- match *self {
- ExprTypeChecked => ExprTypeChecked,
- UncheckedExprHint(_) | UncheckedExprNoHint => UncheckedExprNoHint,
- }
- }
- fn checked_or(&self, ty: Ty<'tcx>) -> EvalHint<'tcx> {
- match *self {
- ExprTypeChecked => ExprTypeChecked,
- _ => UncheckedExprHint(ty),
+ TypeckError => simple!("type-checking failed"),
}
}
}
-macro_rules! signal {
- ($e:expr, $exn:expr) => {
- return Err(ConstEvalErr { span: $e.span, kind: $exn })
- }
-}
+pub type EvalResult<'tcx> = Result<ConstVal<'tcx>, ConstEvalErr<'tcx>>;
+pub type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
- e: &Expr,
- ty_hint: EvalHint<'tcx>) -> EvalResult {
+ e: &Expr) -> EvalResult<'tcx> {
let tcx = cx.tcx;
- // Try to compute the type of the expression based on the EvalHint.
- // (See also the definition of EvalHint, and the FIXME above EvalHint.)
- let ety = match ty_hint {
- ExprTypeChecked => {
- // After type-checking, expr_ty is guaranteed to succeed.
- cx.tables.map(|tables| tables.expr_ty(e))
- }
- UncheckedExprHint(ty) => {
- // Use the type hint; it's not guaranteed to be right, but it's
- // usually good enough.
- Some(ty)
- }
- UncheckedExprNoHint => {
- // This expression might not be type-checked, and we have no hint.
- // Try to query the context for a type anyway; we might get lucky
- // (for example, if the expression was imported from another crate).
- cx.tables.and_then(|tables| tables.expr_ty_opt(e))
- }
+ let ety = cx.tables.expr_ty(e);
+
+ // Avoid applying substitutions if they're empty, that'd ICE.
+ let ety = if cx.substs.is_empty() {
+ ety
+ } else {
+ ety.subst(tcx, cx.substs)
};
+
let result = match e.node {
hir::ExprUnary(hir::UnNeg, ref inner) => {
// unary neg literals already got their sign during creation
const I32_OVERFLOW: u128 = i32::min_value() as u32 as u128;
const I64_OVERFLOW: u128 = i64::min_value() as u64 as u128;
const I128_OVERFLOW: u128 = i128::min_value() as u128;
- match (&lit.node, ety.map(|t| &t.sty)) {
- (&LitKind::Int(I8_OVERFLOW, _), Some(&ty::TyInt(IntTy::I8))) |
+ match (&lit.node, &ety.sty) {
+ (&LitKind::Int(I8_OVERFLOW, _), &ty::TyInt(IntTy::I8)) |
(&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
return Ok(Integral(I8(i8::min_value())))
},
- (&LitKind::Int(I16_OVERFLOW, _), Some(&ty::TyInt(IntTy::I16))) |
+ (&LitKind::Int(I16_OVERFLOW, _), &ty::TyInt(IntTy::I16)) |
(&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
return Ok(Integral(I16(i16::min_value())))
},
- (&LitKind::Int(I32_OVERFLOW, _), Some(&ty::TyInt(IntTy::I32))) |
+ (&LitKind::Int(I32_OVERFLOW, _), &ty::TyInt(IntTy::I32)) |
(&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
return Ok(Integral(I32(i32::min_value())))
},
- (&LitKind::Int(I64_OVERFLOW, _), Some(&ty::TyInt(IntTy::I64))) |
+ (&LitKind::Int(I64_OVERFLOW, _), &ty::TyInt(IntTy::I64)) |
(&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
return Ok(Integral(I64(i64::min_value())))
},
- (&LitKind::Int(I128_OVERFLOW, _), Some(&ty::TyInt(IntTy::I128))) |
+ (&LitKind::Int(I128_OVERFLOW, _), &ty::TyInt(IntTy::I128)) |
(&LitKind::Int(I128_OVERFLOW, Signed(IntTy::I128)), _) => {
return Ok(Integral(I128(i128::min_value())))
},
- (&LitKind::Int(n, _), Some(&ty::TyInt(IntTy::Is))) |
+ (&LitKind::Int(n, _), &ty::TyInt(IntTy::Is)) |
(&LitKind::Int(n, Signed(IntTy::Is)), _) => {
match tcx.sess.target.int_type {
IntTy::I16 => if n == I16_OVERFLOW {
IntTy::I64 => if n == I64_OVERFLOW {
return Ok(Integral(Isize(Is64(i64::min_value()))));
},
- _ => bug!(),
+ _ => span_bug!(e.span, "typeck error")
}
},
_ => {},
}
}
- match cx.eval(inner, ty_hint)? {
+ match cx.eval(inner)? {
Float(f) => Float(-f),
Integral(i) => Integral(math!(e, -i)),
const_val => signal!(e, NegateOn(const_val)),
}
}
hir::ExprUnary(hir::UnNot, ref inner) => {
- match cx.eval(inner, ty_hint)? {
+ match cx.eval(inner)? {
Integral(i) => Integral(math!(e, !i)),
Bool(b) => Bool(!b),
const_val => signal!(e, NotOn(const_val)),
}
hir::ExprUnary(hir::UnDeref, _) => signal!(e, UnimplementedConstVal("deref operation")),
hir::ExprBinary(op, ref a, ref b) => {
- let b_ty = match op.node {
- hir::BiShl | hir::BiShr => ty_hint.erase_hint(),
- _ => ty_hint
- };
// technically, if we don't have type hints, but integral eval
// gives us a type through a type-suffix, cast or const def type
// we need to re-eval the other value of the BinOp if it was
// not inferred
- match (cx.eval(a, ty_hint)?,
- cx.eval(b, b_ty)?) {
+ match (cx.eval(a)?, cx.eval(b)?) {
(Float(a), Float(b)) => {
use std::cmp::Ordering::*;
match op.node {
hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
- _ => signal!(e, InvalidOpForFloats(op.node)),
+ _ => span_bug!(e.span, "typeck error"),
}
}
(Integral(a), Integral(b)) => {
hir::BiNe => Bool(math!(e, a.try_cmp(b)) != Equal),
hir::BiGe => Bool(math!(e, a.try_cmp(b)) != Less),
hir::BiGt => Bool(math!(e, a.try_cmp(b)) == Greater),
- _ => signal!(e, InvalidOpForInts(op.node)),
+ _ => span_bug!(e.span, "typeck error"),
}
}
(Bool(a), Bool(b)) => {
hir::BiLe => a <= b,
hir::BiGe => a >= b,
hir::BiGt => a > b,
- _ => signal!(e, InvalidOpForBools(op.node)),
+ _ => span_bug!(e.span, "typeck error"),
})
}
_ => signal!(e, MiscBinaryOp),
}
}
- hir::ExprCast(ref base, ref target_ty) => {
- let ety = tcx.ast_ty_to_prim_ty(&target_ty).or(ety)
- .unwrap_or_else(|| {
- tcx.sess.span_fatal(target_ty.span,
- "target type not found for const cast")
- });
-
- let base_hint = if let ExprTypeChecked = ty_hint {
- ExprTypeChecked
- } else {
- match cx.tables.and_then(|tables| tables.expr_ty_opt(&base)) {
- Some(t) => UncheckedExprHint(t),
- None => ty_hint
- }
- };
-
- let val = match cx.eval(base, base_hint) {
- Ok(val) => val,
- Err(ConstEvalErr { kind: ErroneousReferencedConstant(
- box ConstEvalErr { kind: TypeMismatch(_, val), .. }), .. }) |
- Err(ConstEvalErr { kind: TypeMismatch(_, val), .. }) => {
- // Something like `5i8 as usize` doesn't need a type hint for the base
- // instead take the type hint from the inner value
- let hint = match val.int_type() {
- Some(IntType::UnsignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_uint(ty)),
- Some(IntType::SignedInt(ty)) => ty_hint.checked_or(tcx.mk_mach_int(ty)),
- // we had a type hint, so we can't have an unknown type
- None => bug!(),
- };
- cx.eval(base, hint)?
- },
- Err(e) => return Err(e),
- };
- match cast_const(tcx, val, ety) {
+ hir::ExprCast(ref base, _) => {
+ match cast_const(tcx, cx.eval(base)?, ety) {
Ok(val) => val,
Err(kind) => return Err(ConstEvalErr { span: e.span, kind: kind }),
}
}
hir::ExprPath(ref qpath) => {
- let def = cx.tables.map(|tables| tables.qpath_def(qpath, e.id)).unwrap_or_else(|| {
- // There are no tables so we can only handle already-resolved HIR.
- match *qpath {
- hir::QPath::Resolved(_, ref path) => path.def,
- hir::QPath::TypeRelative(..) => Def::Err
- }
- });
- match def {
+ let substs = cx.tables.node_id_item_substs(e.id)
+ .unwrap_or_else(|| tcx.intern_substs(&[]));
+
+ // Avoid applying substitutions if they're empty, that'd ICE.
+ let substs = if cx.substs.is_empty() {
+ substs
+ } else {
+ substs.subst(tcx, cx.substs)
+ };
+
+ match cx.tables.qpath_def(qpath, e.id) {
Def::Const(def_id) |
Def::AssociatedConst(def_id) => {
- let substs = if let ExprTypeChecked = ty_hint {
- Some(cx.tables.and_then(|tables| tables.node_id_item_substs(e.id))
- .unwrap_or_else(|| tcx.intern_substs(&[])))
- } else {
- None
- };
- if let Some((expr, tables, ty)) = lookup_const_by_id(tcx, def_id, substs) {
- let item_hint = match ty {
- Some(ty) => ty_hint.checked_or(ty),
- None => ty_hint,
- };
- let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
- match cx.eval(expr, item_hint) {
+ if let Some((expr, tables)) = lookup_const_by_id(tcx, def_id, substs) {
+ let cx = ConstContext::with_tables(tcx, tables);
+ match cx.eval(expr) {
Ok(val) => val,
+ Err(ConstEvalErr { kind: TypeckError, .. }) => {
+ signal!(e, TypeckError);
+ }
Err(err) => {
debug!("bad reference: {:?}, {:?}", err.description(), err.span);
signal!(e, ErroneousReferencedConstant(box err))
},
}
} else {
- signal!(e, NonConstPath);
+ signal!(e, TypeckError);
}
},
Def::VariantCtor(variant_def, ..) => {
if let Some((expr, tables)) = lookup_variant_by_id(tcx, variant_def) {
- let cx = ConstContext { tcx: tcx, tables: tables, fn_args: None };
- match cx.eval(expr, ty_hint) {
+ let cx = ConstContext::with_tables(tcx, tables);
+ match cx.eval(expr) {
Ok(val) => val,
+ Err(ConstEvalErr { kind: TypeckError, .. }) => {
+ signal!(e, TypeckError);
+ }
Err(err) => {
debug!("bad reference: {:?}, {:?}", err.description(), err.span);
signal!(e, ErroneousReferencedConstant(box err))
signal!(e, NonConstPath);
}
},
- Def::Method(id) | Def::Fn(id) => Function(id),
- Def::Err => signal!(e, UnresolvedPath),
+ Def::Method(id) | Def::Fn(id) => Function(id, substs),
+ Def::Err => span_bug!(e.span, "typeck error"),
_ => signal!(e, NonConstPath),
}
}
hir::ExprCall(ref callee, ref args) => {
- let sub_ty_hint = ty_hint.erase_hint();
- let callee_val = cx.eval(callee, sub_ty_hint)?;
- let did = match callee_val {
- Function(did) => did,
+ let (did, substs) = match cx.eval(callee)? {
+ Function(did, substs) => (did, substs),
Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
callee => signal!(e, CallOn(callee)),
};
let mut call_args = DefIdMap();
for (arg, arg_expr) in arg_defs.into_iter().zip(args.iter()) {
- let arg_hint = ty_hint.erase_hint();
- let arg_val = cx.eval(arg_expr, arg_hint)?;
+ let arg_val = cx.eval(arg_expr)?;
debug!("const call arg: {:?}", arg);
if let Some(def_id) = arg {
assert!(call_args.insert(def_id, arg_val).is_none());
let callee_cx = ConstContext {
tcx: tcx,
tables: tables,
+ substs: substs,
fn_args: Some(call_args)
};
- callee_cx.eval(&body.value, ty_hint)?
+ callee_cx.eval(&body.value)?
},
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
Ok(val) => val,
},
hir::ExprBlock(ref block) => {
match block.expr {
- Some(ref expr) => cx.eval(expr, ty_hint)?,
- None => signal!(e, UnimplementedConstVal("empty block")),
+ Some(ref expr) => cx.eval(expr)?,
+ None => Tuple(vec![]),
}
}
- hir::ExprType(ref e, _) => cx.eval(e, ty_hint)?,
+ hir::ExprType(ref e, _) => cx.eval(e)?,
hir::ExprTup(ref fields) => {
- let field_hint = ty_hint.erase_hint();
- Tuple(fields.iter().map(|e| cx.eval(e, field_hint)).collect::<Result<_, _>>()?)
+ Tuple(fields.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
}
hir::ExprStruct(_, ref fields, _) => {
- let field_hint = ty_hint.erase_hint();
Struct(fields.iter().map(|f| {
- cx.eval(&f.expr, field_hint).map(|v| (f.name.node, v))
+ cx.eval(&f.expr).map(|v| (f.name.node, v))
}).collect::<Result<_, _>>()?)
}
hir::ExprIndex(ref arr, ref idx) => {
if !tcx.sess.features.borrow().const_indexing {
signal!(e, IndexOpFeatureGated);
}
- let arr_hint = ty_hint.erase_hint();
- let arr = cx.eval(arr, arr_hint)?;
- let idx_hint = ty_hint.checked_or(tcx.types.usize);
- let idx = match cx.eval(idx, idx_hint)? {
+ let arr = cx.eval(arr)?;
+ let idx = match cx.eval(idx)? {
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
- Integral(_) => bug!(),
- _ => signal!(idx, IndexNotInt),
+ _ => signal!(idx, IndexNotUsize),
};
assert_eq!(idx as usize as u64, idx);
match arr {
}
}
hir::ExprArray(ref v) => {
- let elem_hint = ty_hint.erase_hint();
- Array(v.iter().map(|e| cx.eval(e, elem_hint)).collect::<Result<_, _>>()?)
+ Array(v.iter().map(|e| cx.eval(e)).collect::<Result<_, _>>()?)
}
- hir::ExprRepeat(ref elem, count) => {
- let elem_hint = ty_hint.erase_hint();
- let len_hint = ty_hint.checked_or(tcx.types.usize);
- let n = if let Some(ty) = ety {
- // For cross-crate constants, we have the type already,
- // but not the body for `count`, so use the type.
- match ty.sty {
- ty::TyArray(_, n) => n as u64,
- _ => bug!()
- }
- } else {
- let n = &tcx.hir.body(count).value;
- match ConstContext::new(tcx, count).eval(n, len_hint)? {
- Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
- Integral(_) => signal!(e, RepeatCountNotNatural),
- _ => signal!(e, RepeatCountNotInt),
- }
+ hir::ExprRepeat(ref elem, _) => {
+ let n = match ety.sty {
+ ty::TyArray(_, n) => n as u64,
+ _ => span_bug!(e.span, "typeck error")
};
- Repeat(Box::new(cx.eval(elem, elem_hint)?), n)
+ Repeat(Box::new(cx.eval(elem)?), n)
},
hir::ExprTupField(ref base, index) => {
- let base_hint = ty_hint.erase_hint();
- let c = cx.eval(base, base_hint)?;
+ let c = cx.eval(base)?;
if let Tuple(ref fields) = c {
- if let Some(elem) = fields.get(index.node) {
- elem.clone()
- } else {
- signal!(e, TupleIndexOutOfBounds);
- }
+ fields[index.node].clone()
} else {
signal!(base, ExpectedConstTuple);
}
}
hir::ExprField(ref base, field_name) => {
- let base_hint = ty_hint.erase_hint();
- let c = cx.eval(base, base_hint)?;
+ let c = cx.eval(base)?;
if let Struct(ref fields) = c {
if let Some(f) = fields.get(&field_name.node) {
f.clone()
_ => signal!(e, MiscCatchAll)
};
- match (ety.map(|t| &t.sty), result) {
- (Some(ref ty_hint), Integral(i)) => match infer(i, tcx, ty_hint) {
- Ok(inferred) => Ok(Integral(inferred)),
- Err(err) => signal!(e, err),
- },
- (_, result) => Ok(result),
- }
-}
-
-fn infer<'a, 'tcx>(i: ConstInt,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ty_hint: &ty::TypeVariants<'tcx>)
- -> Result<ConstInt, ErrKind> {
- use syntax::ast::*;
-
- match (ty_hint, i) {
- (&ty::TyInt(IntTy::I8), result @ I8(_)) => Ok(result),
- (&ty::TyInt(IntTy::I16), result @ I16(_)) => Ok(result),
- (&ty::TyInt(IntTy::I32), result @ I32(_)) => Ok(result),
- (&ty::TyInt(IntTy::I64), result @ I64(_)) => Ok(result),
- (&ty::TyInt(IntTy::I128), result @ I128(_)) => Ok(result),
- (&ty::TyInt(IntTy::Is), result @ Isize(_)) => Ok(result),
-
- (&ty::TyUint(UintTy::U8), result @ U8(_)) => Ok(result),
- (&ty::TyUint(UintTy::U16), result @ U16(_)) => Ok(result),
- (&ty::TyUint(UintTy::U32), result @ U32(_)) => Ok(result),
- (&ty::TyUint(UintTy::U64), result @ U64(_)) => Ok(result),
- (&ty::TyUint(UintTy::U128), result @ U128(_)) => Ok(result),
- (&ty::TyUint(UintTy::Us), result @ Usize(_)) => Ok(result),
-
- (&ty::TyInt(IntTy::I8), Infer(i)) => Ok(I8(i as i128 as i8)),
- (&ty::TyInt(IntTy::I16), Infer(i)) => Ok(I16(i as i128 as i16)),
- (&ty::TyInt(IntTy::I32), Infer(i)) => Ok(I32(i as i128 as i32)),
- (&ty::TyInt(IntTy::I64), Infer(i)) => Ok(I64(i as i128 as i64)),
- (&ty::TyInt(IntTy::I128), Infer(i)) => Ok(I128(i as i128)),
- (&ty::TyInt(IntTy::Is), Infer(i)) => {
- Ok(Isize(ConstIsize::new_truncating(i as i128, tcx.sess.target.int_type)))
- },
-
- (&ty::TyInt(IntTy::I8), InferSigned(i)) => Ok(I8(i as i8)),
- (&ty::TyInt(IntTy::I16), InferSigned(i)) => Ok(I16(i as i16)),
- (&ty::TyInt(IntTy::I32), InferSigned(i)) => Ok(I32(i as i32)),
- (&ty::TyInt(IntTy::I64), InferSigned(i)) => Ok(I64(i as i64)),
- (&ty::TyInt(IntTy::I128), InferSigned(i)) => Ok(I128(i)),
- (&ty::TyInt(IntTy::Is), InferSigned(i)) => {
- Ok(Isize(ConstIsize::new_truncating(i, tcx.sess.target.int_type)))
- },
-
- (&ty::TyUint(UintTy::U8), Infer(i)) => Ok(U8(i as u8)),
- (&ty::TyUint(UintTy::U16), Infer(i)) => Ok(U16(i as u16)),
- (&ty::TyUint(UintTy::U32), Infer(i)) => Ok(U32(i as u32)),
- (&ty::TyUint(UintTy::U64), Infer(i)) => Ok(U64(i as u64)),
- (&ty::TyUint(UintTy::U128), Infer(i)) => Ok(U128(i)),
- (&ty::TyUint(UintTy::Us), Infer(i)) => {
- Ok(Usize(ConstUsize::new_truncating(i, tcx.sess.target.uint_type)))
- },
- (&ty::TyUint(_), InferSigned(_)) => Err(IntermediateUnsignedNegative),
-
- (&ty::TyInt(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
- (&ty::TyUint(ity), i) => Err(TypeMismatch(ity.to_string(), i)),
-
- (&ty::TyAdt(adt, _), i) if adt.is_enum() => {
- let hints = tcx.lookup_repr_hints(adt.did);
- let int_ty = tcx.enum_repr_type(hints.iter().next());
- infer(i, tcx, &int_ty.to_ty(tcx).sty)
- },
- (_, i) => Err(BadType(ConstVal::Integral(i))),
- }
+ Ok(result)
}
fn resolve_trait_associated_const<'a, 'tcx: 'a>(
tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_item_id: DefId,
- default_value: Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)>,
+ default_value: Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>,
trait_id: DefId,
rcvr_substs: &'tcx Substs<'tcx>
-) -> Option<(&'tcx Expr, Option<&'a ty::TypeckTables<'tcx>>, Option<ty::Ty<'tcx>>)>
+) -> Option<(&'tcx Expr, &'a ty::TypeckTables<'tcx>)>
{
let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, rcvr_substs));
debug!("resolve_trait_associated_const: trait_ref={:?}",
trait_ref);
tcx.populate_implementations_for_trait_if_necessary(trait_id);
- tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
let mut selcx = traits::SelectionContext::new(&infcx);
let obligation = traits::Obligation::new(traits::ObligationCause::dummy(),
trait_ref.to_poly_trait_predicate());
let ac = tcx.associated_items(impl_data.impl_def_id)
.find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
match ac {
- Some(ic) => lookup_const_by_id(tcx, ic.def_id, None),
+ Some(ic) => lookup_const_by_id(tcx, ic.def_id, Substs::empty()),
None => default_value,
}
}
})
}
-fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstInt, ty: ty::Ty) -> CastResult {
+fn cast_const_int<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ val: ConstInt,
+ ty: Ty<'tcx>)
+ -> CastResult<'tcx> {
let v = val.to_u128_unchecked();
match ty.sty {
ty::TyBool if v == 0 => Ok(Bool(false)),
ty::TyUint(ast::UintTy::Us) => {
Ok(Integral(Usize(ConstUsize::new_truncating(v, tcx.sess.target.uint_type))))
},
- ty::TyFloat(ast::FloatTy::F64) => match val.erase_type() {
- Infer(u) => Ok(Float(F64(u as f64))),
- InferSigned(i) => Ok(Float(F64(i as f64))),
- _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
- },
- ty::TyFloat(ast::FloatTy::F32) => match val.erase_type() {
- Infer(u) => Ok(Float(F32(u as f32))),
- InferSigned(i) => Ok(Float(F32(i as f32))),
- _ => bug!("ConstInt::erase_type returned something other than Infer/InferSigned"),
- },
+ ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(val.to_f64()))),
+ ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(val.to_f32()))),
ty::TyRawPtr(_) => Err(ErrKind::UnimplementedConstVal("casting an address to a raw ptr")),
- ty::TyChar => match infer(val, tcx, &ty::TyUint(ast::UintTy::U8)) {
- Ok(U8(u)) => Ok(Char(u as char)),
- // can only occur before typeck, typeck blocks `T as char` for `T` != `u8`
- _ => Err(CharCast(val)),
+ ty::TyChar => match val {
+ U8(u) => Ok(Char(u as char)),
+ _ => bug!(),
},
- _ => Err(CannotCast),
+ _ => bug!(),
}
}
fn cast_const_float<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
val: ConstFloat,
- ty: ty::Ty) -> CastResult {
+ ty: Ty<'tcx>) -> CastResult<'tcx> {
match ty.sty {
ty::TyInt(_) | ty::TyUint(_) => {
let i = match val {
- F32(f) if f >= 0.0 => Infer(f as u128),
- FInfer { f64: f, .. } |
- F64(f) if f >= 0.0 => Infer(f as u128),
+ F32(f) if f >= 0.0 => U128(f as u128),
+ F64(f) if f >= 0.0 => U128(f as u128),
- F32(f) => InferSigned(f as i128),
- FInfer { f64: f, .. } |
- F64(f) => InferSigned(f as i128)
+ F32(f) => I128(f as i128),
+ F64(f) => I128(f as i128)
};
- if let (InferSigned(_), &ty::TyUint(_)) = (i, &ty.sty) {
+ if let (I128(_), &ty::TyUint(_)) = (i, &ty.sty) {
return Err(CannotCast);
}
}
ty::TyFloat(ast::FloatTy::F64) => Ok(Float(F64(match val {
F32(f) => f as f64,
- FInfer { f64: f, .. } | F64(f) => f
+ F64(f) => f
}))),
ty::TyFloat(ast::FloatTy::F32) => Ok(Float(F32(match val {
F64(f) => f as f32,
- FInfer { f32: f, .. } | F32(f) => f
+ F32(f) => f
}))),
_ => Err(CannotCast),
}
}
-fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, val: ConstVal, ty: ty::Ty) -> CastResult {
+fn cast_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ val: ConstVal<'tcx>,
+ ty: Ty<'tcx>)
+ -> CastResult<'tcx> {
match val {
Integral(i) => cast_const_int(tcx, i, ty),
- Bool(b) => cast_const_int(tcx, Infer(b as u128), ty),
+ Bool(b) => cast_const_int(tcx, U8(b as u8), ty),
Float(f) => cast_const_float(tcx, f, ty),
- Char(c) => cast_const_int(tcx, Infer(c as u128), ty),
- Function(_) => Err(UnimplementedConstVal("casting fn pointers")),
+ Char(c) => cast_const_int(tcx, U32(c as u32), ty),
+ Function(..) => Err(UnimplementedConstVal("casting fn pointers")),
ByteStr(b) => match ty.sty {
ty::TyRawPtr(_) => {
Err(ErrKind::UnimplementedConstVal("casting a bytestr to a raw ptr"))
fn lit_to_const<'a, 'tcx>(lit: &ast::LitKind,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ty_hint: Option<Ty<'tcx>>)
- -> Result<ConstVal, ErrKind> {
+ mut ty: Ty<'tcx>)
+ -> Result<ConstVal<'tcx>, ErrKind<'tcx>> {
use syntax::ast::*;
use syntax::ast::LitIntType::*;
+
+ if let ty::TyAdt(adt, _) = ty.sty {
+ if adt.is_enum() {
+ ty = adt.repr.discr_type().to_ty(tcx)
+ }
+ }
+
match *lit {
LitKind::Str(ref s, _) => Ok(Str(s.as_str())),
LitKind::ByteStr(ref data) => Ok(ByteStr(data.clone())),
LitKind::Byte(n) => Ok(Integral(U8(n))),
- LitKind::Int(n, Signed(ity)) => {
- infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral)
- },
-
- // FIXME: this should become u128.
- LitKind::Int(n, Unsuffixed) => {
- match ty_hint.map(|t| &t.sty) {
- Some(&ty::TyInt(ity)) => {
- infer(InferSigned(n as i128), tcx, &ty::TyInt(ity)).map(Integral)
- },
- Some(&ty::TyUint(uty)) => {
- infer(Infer(n as u128), tcx, &ty::TyUint(uty)).map(Integral)
- },
- None => Ok(Integral(Infer(n as u128))),
- Some(&ty::TyAdt(adt, _)) => {
- let hints = tcx.lookup_repr_hints(adt.did);
- let int_ty = tcx.enum_repr_type(hints.iter().next());
- infer(Infer(n as u128), tcx, &int_ty.to_ty(tcx).sty).map(Integral)
- },
- Some(ty_hint) => bug!("bad ty_hint: {:?}, {:?}", ty_hint, lit),
+ LitKind::Int(n, hint) => {
+ match (&ty.sty, hint) {
+ (&ty::TyInt(ity), _) |
+ (_, Signed(ity)) => {
+ Ok(Integral(ConstInt::new_signed_truncating(n as i128,
+ ity, tcx.sess.target.int_type)))
+ }
+ (&ty::TyUint(uty), _) |
+ (_, Unsigned(uty)) => {
+ Ok(Integral(ConstInt::new_unsigned_truncating(n as u128,
+ uty, tcx.sess.target.uint_type)))
+ }
+ _ => bug!()
}
- },
- LitKind::Int(n, Unsigned(ity)) => {
- infer(Infer(n as u128), tcx, &ty::TyUint(ity)).map(Integral)
- },
-
+ }
LitKind::Float(n, fty) => {
- parse_float(&n.as_str(), Some(fty)).map(Float)
+ parse_float(&n.as_str(), fty).map(Float)
}
LitKind::FloatUnsuffixed(n) => {
- let fty_hint = match ty_hint.map(|t| &t.sty) {
- Some(&ty::TyFloat(fty)) => Some(fty),
- _ => None
+ let fty = match ty.sty {
+ ty::TyFloat(fty) => fty,
+ _ => bug!()
};
- parse_float(&n.as_str(), fty_hint).map(Float)
+ parse_float(&n.as_str(), fty).map(Float)
}
LitKind::Bool(b) => Ok(Bool(b)),
LitKind::Char(c) => Ok(Char(c)),
}
}
-fn parse_float(num: &str, fty_hint: Option<ast::FloatTy>)
- -> Result<ConstFloat, ErrKind> {
- let val = match fty_hint {
- Some(ast::FloatTy::F32) => num.parse::<f32>().map(F32),
- Some(ast::FloatTy::F64) => num.parse::<f64>().map(F64),
- None => {
- num.parse::<f32>().and_then(|f32| {
- num.parse::<f64>().map(|f64| {
- FInfer { f32: f32, f64: f64 }
- })
- })
- }
+fn parse_float<'tcx>(num: &str, fty: ast::FloatTy)
+ -> Result<ConstFloat, ErrKind<'tcx>> {
+ let val = match fty {
+ ast::FloatTy::F32 => num.parse::<f32>().map(F32),
+ ast::FloatTy::F64 => num.parse::<f64>().map(F64)
};
val.map_err(|_| {
// FIXME(#31407) this is only necessary because float parsing is buggy
a: &Expr,
b: &Expr) -> Result<Ordering, ErrorReported> {
let tcx = self.tcx;
- let a = match self.eval(a, ExprTypeChecked) {
+ let a = match self.eval(a) {
Ok(a) => a,
Err(e) => {
- report_const_eval_err(tcx, &e, a.span, "expression").emit();
+ report_const_eval_err(tcx, &e, a.span, "expression");
return Err(ErrorReported);
}
};
- let b = match self.eval(b, ExprTypeChecked) {
+ let b = match self.eval(b) {
Ok(b) => b,
Err(e) => {
- report_const_eval_err(tcx, &e, b.span, "expression").emit();
+ report_const_eval_err(tcx, &e, b.span, "expression");
return Err(ErrorReported);
}
};
reason: &str)
-> Result<usize, ErrorReported>
{
- let hint = UncheckedExprHint(tcx.types.usize);
let count_expr = &tcx.hir.body(count).value;
- match ConstContext::new(tcx, count).eval(count_expr, hint) {
+ match ConstContext::new(tcx, count).eval(count_expr) {
Ok(Integral(Usize(count))) => {
let val = count.as_u64(tcx.sess.target.uint_type);
assert_eq!(val as usize as u64, val);
Ok(val as usize)
},
- Ok(const_val) => {
- struct_span_err!(tcx.sess, count_expr.span, E0306,
- "expected `usize` for {}, found {}",
- reason,
- const_val.description())
- .span_label(count_expr.span, &format!("expected `usize`"))
- .emit();
-
- Err(ErrorReported)
- }
+ Ok(_) |
+ Err(ConstEvalErr { kind: TypeckError, .. }) => Err(ErrorReported),
Err(err) => {
- let mut diag = report_const_eval_err(
+ let mut diag = build_const_eval_err(
tcx, &err, count_expr.span, reason);
if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
+#![deny(warnings)]
#![feature(rustc_private)]
#![feature(staged_api)]
use syntax_pos::Span;
#[derive(Clone, Debug)]
-pub enum PatternError {
+pub enum PatternError<'tcx> {
StaticInPattern(Span),
- ConstEval(eval::ConstEvalErr),
+ ConstEval(eval::ConstEvalErr<'tcx>),
}
#[derive(Copy, Clone, Debug)]
},
Constant {
- value: ConstVal,
+ value: ConstVal<'tcx>,
},
Range {
- lo: ConstVal,
- hi: ConstVal,
+ lo: ConstVal<'tcx>,
+ hi: ConstVal<'tcx>,
end: RangeEnd,
},
ConstVal::Char(c) => write!(f, "{:?}", c),
ConstVal::Struct(_) |
ConstVal::Tuple(_) |
- ConstVal::Function(_) |
+ ConstVal::Function(..) |
ConstVal::Array(..) |
ConstVal::Repeat(..) => bug!("{:?} not printable in a pattern", value)
}
pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
pub tables: &'a ty::TypeckTables<'gcx>,
- pub errors: Vec<PatternError>,
+ pub errors: Vec<PatternError<'tcx>>,
}
impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
let tcx = self.tcx.global_tcx();
let substs = self.tables.node_id_item_substs(id)
.unwrap_or_else(|| tcx.intern_substs(&[]));
- match eval::lookup_const_by_id(tcx, def_id, Some(substs)) {
- Some((const_expr, const_tables, _const_ty)) => {
+ match eval::lookup_const_by_id(tcx, def_id, substs) {
+ Some((const_expr, const_tables)) => {
// Enter the inlined constant's tables temporarily.
let old_tables = self.tables;
- self.tables = const_tables.expect("missing tables after typeck");
+ self.tables = const_tables;
let pat = self.lower_const_expr(const_expr, pat_id, span);
self.tables = old_tables;
return pat;
fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
- match const_cx.eval(expr, eval::EvalHint::ExprTypeChecked) {
+ match const_cx.eval(expr) {
Ok(value) => {
PatternKind::Constant { value: value }
}
}
CloneImpls!{ <'tcx>
- Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal, Region,
+ Span, Field, Mutability, ast::Name, ast::NodeId, usize, ConstVal<'tcx>, Region,
Ty<'tcx>, BindingMode<'tcx>, &'tcx AdtDef,
&'tcx Substs<'tcx>, &'tcx Kind<'tcx>
}
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
pub enum ConstFloat {
F32(f32),
- F64(f64),
-
- // When the type isn't known, we have to operate on both possibilities.
- FInfer {
- f32: f32,
- f64: f64
- }
+ F64(f64)
}
pub use self::ConstFloat::*;
/// Description of the type, not the value
pub fn description(&self) -> &'static str {
match *self {
- FInfer {..} => "float",
F32(_) => "f32",
F64(_) => "f64",
}
match *self {
F32(f) => f.is_nan(),
F64(f) => f.is_nan(),
- FInfer { f32, f64 } => f32.is_nan() || f64.is_nan()
}
}
/// Compares the values if they are of the same type
pub fn try_cmp(self, rhs: Self) -> Result<Ordering, ConstMathErr> {
match (self, rhs) {
- (F64(a), F64(b)) |
- (F64(a), FInfer { f64: b, .. }) |
- (FInfer { f64: a, .. }, F64(b)) |
- (FInfer { f64: a, .. }, FInfer { f64: b, .. }) => {
+ (F64(a), F64(b)) => {
// This is pretty bad but it is the existing behavior.
Ok(if a == b {
Ordering::Equal
})
}
- (F32(a), F32(b)) |
- (F32(a), FInfer { f32: b, .. }) |
- (FInfer { f32: a, .. }, F32(b)) => {
+ (F32(a), F32(b)) => {
Ok(if a == b {
Ordering::Equal
} else if a < b {
impl PartialEq for ConstFloat {
fn eq(&self, other: &Self) -> bool {
match (*self, *other) {
- (F64(a), F64(b)) |
- (F64(a), FInfer { f64: b, .. }) |
- (FInfer { f64: a, .. }, F64(b)) |
- (FInfer { f64: a, .. }, FInfer { f64: b, .. }) => {
+ (F64(a), F64(b)) => {
unsafe{transmute::<_,u64>(a) == transmute::<_,u64>(b)}
}
(F32(a), F32(b)) => {
impl hash::Hash for ConstFloat {
fn hash<H: hash::Hasher>(&self, state: &mut H) {
match *self {
- F64(a) | FInfer { f64: a, .. } => {
+ F64(a) => {
unsafe { transmute::<_,u64>(a) }.hash(state)
}
F32(a) => {
impl ::std::fmt::Display for ConstFloat {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
match *self {
- FInfer { f64, .. } => write!(fmt, "{}", f64),
F32(f) => write!(fmt, "{}f32", f),
F64(f) => write!(fmt, "{}f64", f),
}
type Output = Result<Self, ConstMathErr>;
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
match (self, rhs) {
- (F32(a), F32(b)) |
- (F32(a), FInfer { f32: b, .. }) |
- (FInfer { f32: a, .. }, F32(b)) => Ok(F32(a.$func(b))),
-
- (F64(a), F64(b)) |
- (FInfer { f64: a, .. }, F64(b)) |
- (F64(a), FInfer { f64: b, .. }) => Ok(F64(a.$func(b))),
-
- (FInfer { f32: a32, f64: a64 },
- FInfer { f32: b32, f64: b64 }) => Ok(FInfer {
- f32: a32.$func(b32),
- f64: a64.$func(b64)
- }),
-
+ (F32(a), F32(b)) => Ok(F32(a.$func(b))),
+ (F64(a), F64(b)) => Ok(F64(a.$func(b))),
_ => Err(UnequalTypes(Op::$op)),
}
}
match self {
F32(f) => F32(-f),
F64(f) => F64(-f),
- FInfer { f32, f64 } => FInfer {
- f32: -f32,
- f64: -f64
- }
}
}
}
U64(u64),
U128(u128),
Usize(ConstUsize),
- Infer(u128),
- InferSigned(i128),
}
pub use self::ConstInt::*;
}
impl ConstInt {
- pub fn new_inttype(val: u128, ty: IntType, usize_ty: UintTy, isize_ty: IntTy)
- -> Option<ConstInt> {
- match ty {
- IntType::SignedInt(i) => ConstInt::new_signed(val as i128, i, isize_ty),
- IntType::UnsignedInt(i) => ConstInt::new_unsigned(val, i, usize_ty),
- }
- }
-
/// Creates a new unsigned ConstInt with matching type while also checking that overflow does
/// not happen.
pub fn new_unsigned(val: u128, ty: UintTy, usize_ty: UintTy) -> Option<ConstInt> {
}
}
- /// Creates a new unsigned ConstInt with matching type while also checking that overflow does
+ /// Creates a new signed ConstInt with matching type while also checking that overflow does
/// not happen.
pub fn new_signed(val: i128, ty: IntTy, isize_ty: IntTy) -> Option<ConstInt> {
match ty {
}
}
- /// If either value is `Infer` or `InferSigned`, try to turn the value into the type of
- /// the other value. If both values have no type, don't do anything
- pub fn infer(self, other: Self) -> Result<(Self, Self), ConstMathErr> {
- let inferred = match (self, other) {
- (InferSigned(_), InferSigned(_))
- | (Infer(_), Infer(_)) => self, // no inference possible
- // kindof wrong, you could have had values > I64MAX during computation of a
- (Infer(a @ 0...ubounds::I64MAX), InferSigned(_)) => InferSigned(a as i128),
- (Infer(_), InferSigned(_)) => return Err(ConstMathErr::NotInRange),
- (_, InferSigned(_))
- | (_, Infer(_)) => return other.infer(self).map(|(b, a)| (a, b)),
-
- (Infer(a @ 0...ubounds::I8MAX), I8(_)) => I8(a as i64 as i8),
- (Infer(a @ 0...ubounds::I16MAX), I16(_)) => I16(a as i64 as i16),
- (Infer(a @ 0...ubounds::I32MAX), I32(_)) => I32(a as i64 as i32),
- (Infer(a @ 0...ubounds::I64MAX), I64(_)) => I64(a as i64),
- (Infer(a @ 0...ubounds::I128MAX), I128(_)) => I128(a as i128),
- (Infer(a @ 0...ubounds::I16MAX), Isize(Is16(_))) => Isize(Is16(a as i64 as i16)),
- (Infer(a @ 0...ubounds::I32MAX), Isize(Is32(_))) => Isize(Is32(a as i64 as i32)),
- (Infer(a @ 0...ubounds::I64MAX), Isize(Is64(_))) => Isize(Is64(a as i64)),
- (Infer(a @ 0...ubounds::U8MAX), U8(_)) => U8(a as u8),
- (Infer(a @ 0...ubounds::U16MAX), U16(_)) => U16(a as u16),
- (Infer(a @ 0...ubounds::U32MAX), U32(_)) => U32(a as u32),
- (Infer(a @ 0...ubounds::U64MAX), U64(_)) => U64(a as u64),
- (Infer(a @ 0...ubounds::U128MAX), U128(_)) => U128(a as u128),
- (Infer(a @ 0...ubounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
- (Infer(a @ 0...ubounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
- (Infer(a @ 0...ubounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
-
- (Infer(_), _) => return Err(ConstMathErr::NotInRange),
-
- (InferSigned(a @ ibounds::I8MIN...ibounds::I8MAX), I8(_)) => I8(a as i8),
- (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), I16(_)) => I16(a as i16),
- (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), I32(_)) => I32(a as i32),
- (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), I64(_)) => I64(a as i64),
- (InferSigned(a @ ibounds::I128MIN...ibounds::I128MAX), I128(_)) => I128(a as i128),
- (InferSigned(a @ ibounds::I16MIN...ibounds::I16MAX), Isize(Is16(_))) => {
- Isize(Is16(a as i16))
- },
- (InferSigned(a @ ibounds::I32MIN...ibounds::I32MAX), Isize(Is32(_))) => {
- Isize(Is32(a as i32))
- },
- (InferSigned(a @ ibounds::I64MIN...ibounds::I64MAX), Isize(Is64(_))) => {
- Isize(Is64(a as i64))
- },
- (InferSigned(a @ 0...ibounds::U8MAX), U8(_)) => U8(a as u8),
- (InferSigned(a @ 0...ibounds::U16MAX), U16(_)) => U16(a as u16),
- (InferSigned(a @ 0...ibounds::U32MAX), U32(_)) => U32(a as u32),
- (InferSigned(a @ 0...ibounds::U64MAX), U64(_)) => U64(a as u64),
- (InferSigned(a @ 0...ibounds::I128MAX), U128(_)) => U128(a as u128),
- (InferSigned(a @ 0...ibounds::U16MAX), Usize(Us16(_))) => Usize(Us16(a as u16)),
- (InferSigned(a @ 0...ibounds::U32MAX), Usize(Us32(_))) => Usize(Us32(a as u32)),
- (InferSigned(a @ 0...ibounds::U64MAX), Usize(Us64(_))) => Usize(Us64(a as u64)),
- (InferSigned(_), _) => return Err(ConstMathErr::NotInRange),
- _ => self, // already known types
- };
- Ok((inferred, other))
+ /// Creates a new unsigned ConstInt with matching type.
+ pub fn new_unsigned_truncating(val: u128, ty: UintTy, usize_ty: UintTy) -> ConstInt {
+ match ty {
+ UintTy::U8 => U8(val as u8),
+ UintTy::U16 => U16(val as u16),
+ UintTy::U32 => U32(val as u32),
+ UintTy::U64 => U64(val as u64),
+ UintTy::Us => Usize(ConstUsize::new_truncating(val, usize_ty)),
+ UintTy::U128 => U128(val)
+ }
}
- /// Turn this value into an `Infer` or an `InferSigned`
- pub fn erase_type(self) -> Self {
- match self {
- Infer(i) => Infer(i),
- InferSigned(i) if i < 0 => InferSigned(i),
- I8(i) if i < 0 => InferSigned(i as i128),
- I16(i) if i < 0 => InferSigned(i as i128),
- I32(i) if i < 0 => InferSigned(i as i128),
- I64(i) if i < 0 => InferSigned(i as i128),
- I128(i) if i < 0 => InferSigned(i as i128),
- Isize(Is16(i)) if i < 0 => InferSigned(i as i128),
- Isize(Is32(i)) if i < 0 => InferSigned(i as i128),
- Isize(Is64(i)) if i < 0 => InferSigned(i as i128),
- InferSigned(i) => Infer(i as u128),
- I8(i) => Infer(i as u128),
- I16(i) => Infer(i as u128),
- I32(i) => Infer(i as u128),
- I64(i) => Infer(i as u128),
- I128(i) => Infer(i as u128),
- Isize(Is16(i)) => Infer(i as u128),
- Isize(Is32(i)) => Infer(i as u128),
- Isize(Is64(i)) => Infer(i as u128),
- U8(i) => Infer(i as u128),
- U16(i) => Infer(i as u128),
- U32(i) => Infer(i as u128),
- U64(i) => Infer(i as u128),
- U128(i) => Infer(i as u128),
- Usize(Us16(i)) => Infer(i as u128),
- Usize(Us32(i)) => Infer(i as u128),
- Usize(Us64(i)) => Infer(i as u128),
+ /// Creates a new signed ConstInt with matching type.
+ pub fn new_signed_truncating(val: i128, ty: IntTy, isize_ty: IntTy) -> ConstInt {
+ match ty {
+ IntTy::I8 => I8(val as i8),
+ IntTy::I16 => I16(val as i16),
+ IntTy::I32 => I32(val as i32),
+ IntTy::I64 => I64(val as i64),
+ IntTy::Is => Isize(ConstIsize::new_truncating(val, isize_ty)),
+ IntTy::I128 => I128(val)
}
}
/// Description of the type, not the value
pub fn description(&self) -> &'static str {
match *self {
- Infer(_) => "not yet inferred integral",
- InferSigned(_) => "not yet inferred signed integral",
I8(_) => "i8",
I16(_) => "i16",
I32(_) => "i32",
/// Erases the type and returns a u128.
/// This is not the same as `-5i8 as u128` but as `-5i8 as i128 as u128`
pub fn to_u128_unchecked(self) -> u128 {
- match self.erase_type() {
- ConstInt::Infer(i) => i,
- ConstInt::InferSigned(i) => i as u128,
- _ => unreachable!(),
+ match self {
+ I8(i) => i as i128 as u128,
+ I16(i) => i as i128 as u128,
+ I32(i) => i as i128 as u128,
+ I64(i) => i as i128 as u128,
+ I128(i) => i as i128 as u128,
+ Isize(Is16(i)) => i as i128 as u128,
+ Isize(Is32(i)) => i as i128 as u128,
+ Isize(Is64(i)) => i as i128 as u128,
+ U8(i) => i as u128,
+ U16(i) => i as u128,
+ U32(i) => i as u128,
+ U64(i) => i as u128,
+ U128(i) => i as u128,
+ Usize(Us16(i)) => i as u128,
+ Usize(Us32(i)) => i as u128,
+ Usize(Us64(i)) => i as u128,
}
}
/// Converts the value to a `u128` if it's in the range 0...std::u128::MAX
pub fn to_u128(&self) -> Option<u128> {
match *self {
- Infer(v) => Some(v),
- InferSigned(v) if v >= 0 => Some(v as u128),
I8(v) if v >= 0 => Some(v as u128),
I16(v) if v >= 0 => Some(v as u128),
I32(v) if v >= 0 => Some(v as u128),
}
}
+ pub fn to_f32(self) -> f32 {
+ match self {
+ I8(i) => i as f32,
+ I16(i) => i as f32,
+ I32(i) => i as f32,
+ I64(i) => i as f32,
+ I128(i) => i as f32,
+ Isize(Is16(i)) => i as f32,
+ Isize(Is32(i)) => i as f32,
+ Isize(Is64(i)) => i as f32,
+ U8(i) => i as f32,
+ U16(i) => i as f32,
+ U32(i) => i as f32,
+ U64(i) => i as f32,
+ U128(i) => i as f32,
+ Usize(Us16(i)) => i as f32,
+ Usize(Us32(i)) => i as f32,
+ Usize(Us64(i)) => i as f32,
+ }
+ }
+
+ pub fn to_f64(self) -> f64 {
+ match self {
+ I8(i) => i as f64,
+ I16(i) => i as f64,
+ I32(i) => i as f64,
+ I64(i) => i as f64,
+ I128(i) => i as f64,
+ Isize(Is16(i)) => i as f64,
+ Isize(Is32(i)) => i as f64,
+ Isize(Is64(i)) => i as f64,
+ U8(i) => i as f64,
+ U16(i) => i as f64,
+ U32(i) => i as f64,
+ U64(i) => i as f64,
+ U128(i) => i as f64,
+ Usize(Us16(i)) => i as f64,
+ Usize(Us32(i)) => i as f64,
+ Usize(Us64(i)) => i as f64,
+ }
+ }
+
pub fn is_negative(&self) -> bool {
match *self {
I8(v) => v < 0,
Isize(Is16(v)) => v < 0,
Isize(Is32(v)) => v < 0,
Isize(Is64(v)) => v < 0,
- InferSigned(v) => v < 0,
_ => false,
}
}
/// Compares the values if they are of the same type
pub fn try_cmp(self, rhs: Self) -> Result<::std::cmp::Ordering, ConstMathErr> {
- match self.infer(rhs)? {
+ match (self, rhs) {
(I8(a), I8(b)) => Ok(a.cmp(&b)),
(I16(a), I16(b)) => Ok(a.cmp(&b)),
(I32(a), I32(b)) => Ok(a.cmp(&b)),
(Usize(Us16(a)), Usize(Us16(b))) => Ok(a.cmp(&b)),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(a.cmp(&b)),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(a.cmp(&b)),
- (Infer(a), Infer(b)) => Ok(a.cmp(&b)),
- (InferSigned(a), InferSigned(b)) => Ok(a.cmp(&b)),
_ => Err(CmpBetweenUnequalTypes),
}
}
ConstInt::Usize(ConstUsize::Us16(i)) => ConstInt::Usize(ConstUsize::Us16(add1!(i))),
ConstInt::Usize(ConstUsize::Us32(i)) => ConstInt::Usize(ConstUsize::Us32(add1!(i))),
ConstInt::Usize(ConstUsize::Us64(i)) => ConstInt::Usize(ConstUsize::Us64(add1!(i))),
- ConstInt::Infer(_) | ConstInt::InferSigned(_) => panic!("no type info for const int"),
}
}
- pub fn int_type(self) -> Option<IntType> {
+ pub fn int_type(self) -> IntType {
match self {
- ConstInt::I8(_) => Some(IntType::SignedInt(IntTy::I8)),
- ConstInt::I16(_) => Some(IntType::SignedInt(IntTy::I16)),
- ConstInt::I32(_) => Some(IntType::SignedInt(IntTy::I32)),
- ConstInt::I64(_) => Some(IntType::SignedInt(IntTy::I64)),
- ConstInt::I128(_) => Some(IntType::SignedInt(IntTy::I128)),
- ConstInt::Isize(_) => Some(IntType::SignedInt(IntTy::Is)),
- ConstInt::U8(_) => Some(IntType::UnsignedInt(UintTy::U8)),
- ConstInt::U16(_) => Some(IntType::UnsignedInt(UintTy::U16)),
- ConstInt::U32(_) => Some(IntType::UnsignedInt(UintTy::U32)),
- ConstInt::U64(_) => Some(IntType::UnsignedInt(UintTy::U64)),
- ConstInt::U128(_) => Some(IntType::UnsignedInt(UintTy::U128)),
- ConstInt::Usize(_) => Some(IntType::UnsignedInt(UintTy::Us)),
- _ => None,
+ ConstInt::I8(_) => IntType::SignedInt(IntTy::I8),
+ ConstInt::I16(_) => IntType::SignedInt(IntTy::I16),
+ ConstInt::I32(_) => IntType::SignedInt(IntTy::I32),
+ ConstInt::I64(_) => IntType::SignedInt(IntTy::I64),
+ ConstInt::I128(_) => IntType::SignedInt(IntTy::I128),
+ ConstInt::Isize(_) => IntType::SignedInt(IntTy::Is),
+ ConstInt::U8(_) => IntType::UnsignedInt(UintTy::U8),
+ ConstInt::U16(_) => IntType::UnsignedInt(UintTy::U16),
+ ConstInt::U32(_) => IntType::UnsignedInt(UintTy::U32),
+ ConstInt::U64(_) => IntType::UnsignedInt(UintTy::U64),
+ ConstInt::U128(_) => IntType::UnsignedInt(UintTy::U128),
+ ConstInt::Usize(_) => IntType::UnsignedInt(UintTy::Us),
}
}
}
impl ::std::fmt::Display for ConstInt {
fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
match *self {
- Infer(i) => write!(fmt, "{}", i),
- InferSigned(i) => write!(fmt, "{}", i),
I8(i) => write!(fmt, "{}i8", i),
I16(i) => write!(fmt, "{}i16", i),
I32(i) => write!(fmt, "{}i32", i),
impl ::std::ops::$op for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
- match self.infer(rhs)? {
+ match (self, rhs) {
(I8(a), I8(b)) => a.$checked_func(b).map(I8),
(I16(a), I16(b)) => a.$checked_func(b).map(I16),
(I32(a), I32(b)) => a.$checked_func(b).map(I32),
(Usize(Us16(a)), Usize(Us16(b))) => a.$checked_func(b).map(Us16).map(Usize),
(Usize(Us32(a)), Usize(Us32(b))) => a.$checked_func(b).map(Us32).map(Usize),
(Usize(Us64(a)), Usize(Us64(b))) => a.$checked_func(b).map(Us64).map(Usize),
- (Infer(a), Infer(b)) => a.$checked_func(b).map(Infer),
- (InferSigned(a), InferSigned(b)) => a.$checked_func(b).map(InferSigned),
_ => return Err(UnequalTypes(Op::$op)),
}.ok_or(Overflow(Op::$op))
}
impl ::std::ops::$op for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn $func(self, rhs: Self) -> Result<Self, ConstMathErr> {
- match self.infer(rhs)? {
+ match (self, rhs) {
(I8(a), I8(b)) => Ok(I8(a.$func(b))),
(I16(a), I16(b)) => Ok(I16(a.$func(b))),
(I32(a), I32(b)) => Ok(I32(a.$func(b))),
(Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a.$func(b)))),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a.$func(b)))),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a.$func(b)))),
- (Infer(a), Infer(b)) => Ok(Infer(a.$func(b))),
- (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a.$func(b))),
_ => Err(UnequalTypes(Op::$op)),
}
}
(Isize(_), Isize(Is16(0))) => Err(zerr),
(Isize(_), Isize(Is32(0))) => Err(zerr),
(Isize(_), Isize(Is64(0))) => Err(zerr),
- (InferSigned(_), InferSigned(0)) => Err(zerr),
(U8(_), U8(0)) => Err(zerr),
(U16(_), U16(0)) => Err(zerr),
(Usize(_), Usize(Us16(0))) => Err(zerr),
(Usize(_), Usize(Us32(0))) => Err(zerr),
(Usize(_), Usize(Us64(0))) => Err(zerr),
- (Infer(_), Infer(0)) => Err(zerr),
(I8(::std::i8::MIN), I8(-1)) => Err(Overflow(op)),
(I16(::std::i16::MIN), I16(-1)) => Err(Overflow(op)),
(Isize(Is16(::std::i16::MIN)), Isize(Is16(-1))) => Err(Overflow(op)),
(Isize(Is32(::std::i32::MIN)), Isize(Is32(-1))) => Err(Overflow(op)),
(Isize(Is64(::std::i64::MIN)), Isize(Is64(-1))) => Err(Overflow(op)),
- (InferSigned(I128_MIN), InferSigned(-1)) => Err(Overflow(op)),
_ => Ok(()),
}
impl ::std::ops::Div for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn div(self, rhs: Self) -> Result<Self, ConstMathErr> {
- let (lhs, rhs) = self.infer(rhs)?;
+ let (lhs, rhs) = (self, rhs);
check_division(lhs, rhs, Op::Div, DivisionByZero)?;
match (lhs, rhs) {
(I8(a), I8(b)) => Ok(I8(a/b)),
(Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a/b))),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a/b))),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a/b))),
- (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a/b)),
(U8(a), U8(b)) => Ok(U8(a/b)),
(U16(a), U16(b)) => Ok(U16(a/b)),
(Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a/b))),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a/b))),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a/b))),
- (Infer(a), Infer(b)) => Ok(Infer(a/b)),
_ => Err(UnequalTypes(Op::Div)),
}
impl ::std::ops::Rem for ConstInt {
type Output = Result<Self, ConstMathErr>;
fn rem(self, rhs: Self) -> Result<Self, ConstMathErr> {
- let (lhs, rhs) = self.infer(rhs)?;
+ let (lhs, rhs) = (self, rhs);
// should INT_MIN%-1 be zero or an error?
check_division(lhs, rhs, Op::Rem, RemainderByZero)?;
match (lhs, rhs) {
(Isize(Is16(a)), Isize(Is16(b))) => Ok(Isize(Is16(a%b))),
(Isize(Is32(a)), Isize(Is32(b))) => Ok(Isize(Is32(a%b))),
(Isize(Is64(a)), Isize(Is64(b))) => Ok(Isize(Is64(a%b))),
- (InferSigned(a), InferSigned(b)) => Ok(InferSigned(a%b)),
(U8(a), U8(b)) => Ok(U8(a%b)),
(U16(a), U16(b)) => Ok(U16(a%b)),
(Usize(Us16(a)), Usize(Us16(b))) => Ok(Usize(Us16(a%b))),
(Usize(Us32(a)), Usize(Us32(b))) => Ok(Usize(Us32(a%b))),
(Usize(Us64(a)), Usize(Us64(b))) => Ok(Usize(Us64(a%b))),
- (Infer(a), Infer(b)) => Ok(Infer(a%b)),
_ => Err(UnequalTypes(Op::Rem)),
}
Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shl(b), Op::Shl)))),
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shl(b), Op::Shl)))),
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shl(b), Op::Shl)))),
- Infer(a) => Ok(Infer(overflowing!(a.overflowing_shl(b), Op::Shl))),
- InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shl(b), Op::Shl))),
}
}
}
Usize(Us16(a)) => Ok(Usize(Us16(overflowing!(a.overflowing_shr(b), Op::Shr)))),
Usize(Us32(a)) => Ok(Usize(Us32(overflowing!(a.overflowing_shr(b), Op::Shr)))),
Usize(Us64(a)) => Ok(Usize(Us64(overflowing!(a.overflowing_shr(b), Op::Shr)))),
- Infer(a) => Ok(Infer(overflowing!(a.overflowing_shr(b), Op::Shr))),
- InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_shr(b), Op::Shr))),
}
}
}
a@U8(0) | a@U16(0) | a@U32(0) | a@U64(0) | a@U128(0) |
a@Usize(Us16(0)) | a@Usize(Us32(0)) | a@Usize(Us64(0)) => Ok(a),
U8(_) | U16(_) | U32(_) | U64(_) | U128(_) | Usize(_) => Err(UnsignedNegation),
- Infer(a @ 0...ubounds::I128MAX) => Ok(InferSigned(-(a as i128))),
- Infer(_) => Err(Overflow(Op::Neg)),
- InferSigned(a) => Ok(InferSigned(overflowing!(a.overflowing_neg(), Op::Neg))),
}
}
}
Usize(Us16(a)) => Ok(Usize(Us16(!a))),
Usize(Us32(a)) => Ok(Usize(Us32(!a))),
Usize(Us64(a)) => Ok(Usize(Us64(!a))),
- Infer(a) => Ok(Infer(!a)),
- InferSigned(a) => Ok(InferSigned(!a)),
}
}
}
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
html_favicon_url = "https://doc.rust-lang.org/favicon.ico",
html_root_url = "https://doc.rust-lang.org/nightly/")]
-
+#![deny(warnings)]
#![feature(rustc_private)]
#![feature(staged_api)]
use rustc::middle::privacy::AccessLevels;
use rustc::ty::{self, TyCtxt, Resolutions, GlobalArenas};
use rustc::util::common::time;
-use rustc::util::nodemap::{NodeSet, NodeMap};
+use rustc::util::nodemap::NodeSet;
use rustc::util::fs::rename_or_copy_remove;
use rustc_borrowck as borrowck;
use rustc_incremental::{self, IncrementalHashesMap};
use rustc_incremental::ich::Fingerprint;
use rustc_resolve::{MakeGlobMap, Resolver};
use rustc_metadata::creader::CrateLoader;
-use rustc_metadata::cstore::CStore;
+use rustc_metadata::cstore::{self, CStore};
use rustc_trans::back::{link, write};
use rustc_trans as trans;
use rustc_typeck as typeck;
pub hir_crate: Option<&'a hir::Crate>,
pub hir_map: Option<&'a hir_map::Map<'tcx>>,
pub resolutions: Option<&'a Resolutions>,
- pub analysis: Option<&'a ty::CrateAnalysis<'tcx>>,
+ pub analysis: Option<&'a ty::CrateAnalysis>,
pub tcx: Option<TyCtxt<'a, 'tcx, 'tcx>>,
pub trans: Option<&'a trans::CrateTranslation>,
}
arenas: &'tcx GlobalArenas<'tcx>,
cstore: &'a CStore,
hir_map: &'a hir_map::Map<'tcx>,
- analysis: &'a ty::CrateAnalysis<'static>,
+ analysis: &'a ty::CrateAnalysis,
resolutions: &'a Resolutions,
krate: &'a ast::Crate,
hir_crate: &'a hir::Crate,
out_file: &'a Option<PathBuf>,
krate: Option<&'a ast::Crate>,
hir_crate: &'a hir::Crate,
- analysis: &'a ty::CrateAnalysis<'tcx>,
+ analysis: &'a ty::CrateAnalysis,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
crate_name: &'a str)
-> Self {
pub struct ExpansionResult {
pub expanded_crate: ast::Crate,
pub defs: hir_map::Definitions,
- pub analysis: ty::CrateAnalysis<'static>,
+ pub analysis: ty::CrateAnalysis,
pub resolutions: Resolutions,
pub hir_forest: hir_map::Forest,
}
reachable: NodeSet(),
name: crate_name.to_string(),
glob_map: if resolver.make_glob_map { Some(resolver.glob_map) } else { None },
- hir_ty_to_ty: NodeMap(),
},
resolutions: Resolutions {
freevars: resolver.freevars,
/// structures carrying the results of the analysis.
pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
hir_map: hir_map::Map<'tcx>,
- mut analysis: ty::CrateAnalysis<'tcx>,
+ mut analysis: ty::CrateAnalysis,
resolutions: Resolutions,
arena: &'tcx DroplessArena,
arenas: &'tcx GlobalArenas<'tcx>,
f: F)
-> Result<R, usize>
where F: for<'a> FnOnce(TyCtxt<'a, 'tcx, 'tcx>,
- ty::CrateAnalysis<'tcx>,
+ ty::CrateAnalysis,
IncrementalHashesMap,
CompileResult) -> R
{
let index = stability::Index::new(&hir_map);
+ let mut local_providers = ty::maps::Providers::default();
+ mir::provide(&mut local_providers);
+ typeck::provide(&mut local_providers);
+
+ let mut extern_providers = ty::maps::Providers::default();
+ cstore::provide(&mut extern_providers);
+
TyCtxt::create_and_enter(sess,
+ local_providers,
+ extern_providers,
arenas,
arena,
resolutions,
|| stability::check_unstable_api_usage(tcx));
// passes are timed inside typeck
- analysis.hir_ty_to_ty =
- try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map));
+ try_with_f!(typeck::check_crate(tcx), (tcx, analysis, incremental_hashes_map));
time(time_passes,
"const checking",
// in stage 4 below.
passes.push_hook(box mir::transform::dump_mir::DumpMir);
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("initial"));
- passes.push_pass(
- box mir::transform::qualify_consts::QualifyAndPromoteConstants::default());
+ passes.push_pass(box mir::transform::qualify_consts::QualifyAndPromoteConstants);
passes.push_pass(box mir::transform::type_check::TypeckMir);
passes.push_pass(
box mir::transform::simplify_branches::SimplifyBranches::new("initial"));
fn call_with_pp_support_hir<'tcx, A, B, F>(&self,
sess: &'tcx Session,
hir_map: &hir_map::Map<'tcx>,
- analysis: &ty::CrateAnalysis<'tcx>,
+ analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
arena: &'tcx DroplessArena,
arenas: &'tcx GlobalArenas<'tcx>,
pub fn print_after_hir_lowering<'tcx, 'a: 'tcx>(sess: &'a Session,
hir_map: &hir_map::Map<'tcx>,
- analysis: &ty::CrateAnalysis<'tcx>,
+ analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
input: &Input,
krate: &ast::Crate,
// Instead, we call that function ourselves.
fn print_with_analysis<'tcx, 'a: 'tcx>(sess: &'a Session,
hir_map: &hir_map::Map<'tcx>,
- analysis: &ty::CrateAnalysis<'tcx>,
+ analysis: &ty::CrateAnalysis,
resolutions: &Resolutions,
crate_name: &str,
arena: &'tcx DroplessArena,
} else {
match ppm {
PpmMir => {
- write_mir_pretty(tcx, tcx.mir_map.borrow().keys().into_iter(), &mut out)
+ write_mir_pretty(tcx,
+ tcx.maps.mir.borrow().keys().into_iter(),
+ &mut out)
}
PpmMirCFG => {
write_mir_graphviz(tcx,
- tcx.mir_map.borrow().keys().into_iter(),
+ tcx.maps.mir.borrow().keys().into_iter(),
&mut out)
}
_ => unreachable!(),
let region_map = region::resolve_crate(&sess, &hir_map);
let index = stability::Index::new(&hir_map);
TyCtxt::create_and_enter(&sess,
+ ty::maps::Providers::default(),
+ ty::maps::Providers::default(),
&arenas,
&arena,
resolutions,
index,
"test_crate",
|tcx| {
- tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
body(Env { infcx: &infcx });
let free_regions = FreeRegionMap::new();
}
pub fn t_fn(&self, input_tys: &[Ty<'tcx>], output_ty: Ty<'tcx>) -> Ty<'tcx> {
- self.infcx.tcx.mk_fn_ptr(self.infcx.tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- sig: ty::Binder(self.infcx.tcx.mk_fn_sig(input_tys.iter().cloned(), output_ty, false)),
- }))
+ self.infcx.tcx.mk_fn_ptr(ty::Binder(self.infcx.tcx.mk_fn_sig(
+ input_tys.iter().cloned(),
+ output_ty,
+ false,
+ hir::Unsafety::Normal,
+ Abi::Rust
+ )))
}
pub fn t_nil(&self) -> Ty<'tcx> {
hash_spans: bool,
hash_bodies: bool)
-> Self {
- let check_overflow = tcx.sess.opts.debugging_opts.force_overflow_checks
- .unwrap_or(tcx.sess.opts.debug_assertions);
+ let check_overflow = tcx.sess.overflow_checks();
StrictVersionHashVisitor {
st: st,
ExprIndex(..) => (SawExprIndex, true),
ExprPath(_) => (SawExprPath, false),
ExprAddrOf(m, _) => (SawExprAddrOf(m), false),
- ExprBreak(label, _) => (SawExprBreak(label.map(|l| l.name.as_str())), false),
- ExprAgain(label) => (SawExprAgain(label.map(|l| l.name.as_str())), false),
+ ExprBreak(label, _) => (SawExprBreak(label.ident.map(|i|
+ i.node.name.as_str())), false),
+ ExprAgain(label) => (SawExprAgain(label.ident.map(|i|
+ i.node.name.as_str())), false),
ExprRet(..) => (SawExprRet, false),
ExprInlineAsm(ref a,..) => (SawExprInlineAsm(StableInlineAsm(a)), false),
ExprStruct(..) => (SawExprStruct, false),
trait_items: _,
impl_items: _,
bodies: _,
+
+ trait_impls: _,
+ trait_default_impl: _,
} = *krate;
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
pub struct SerializedDepGraph {
pub edges: Vec<SerializedEdgeSet>,
+ /// These are output nodes that have no incoming edges. We track
+ /// these separately so that when we reload all edges, we don't
+ /// lose track of these nodes.
+ pub bootstrap_outputs: Vec<DepNode<DefPathIndex>>,
+
/// These are hashes of two things:
/// - the HIR nodes in this crate
/// - the metadata nodes from dependent crates we use
impl<'a, 'tcx, 'm> ItemLikeVisitor<'tcx> for DirtyCleanMetadataVisitor<'a, 'tcx, 'm> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
self.check_item(item.id, item.span);
+
+ if let hir::ItemEnum(ref def, _) = item.node {
+ for v in &def.variants {
+ self.check_item(v.node.data.id(), v.span);
+ }
+ }
}
fn visit_trait_item(&mut self, item: &hir::TraitItem) {
}
}
+ // Recreate bootstrap outputs, which are outputs that have no incoming edges (and hence cannot
+ // be dirty).
+ for bootstrap_output in &serialized_dep_graph.bootstrap_outputs {
+ if let Some(n) = retraced.map(bootstrap_output) {
+ if let DepNode::WorkProduct(ref wp) = n {
+ clean_work_products.insert(wp.clone());
+ }
+
+ tcx.dep_graph.with_task(n, || ()); // create the node with no inputs
+ }
+ }
+
// Subtle. Sometimes we have intermediate nodes that we can't recreate in the new graph.
// This is pretty unusual but it arises in a scenario like this:
//
use rustc::dep_graph::{DepGraphQuery, DepNode};
use rustc::hir::def_id::DefId;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::graph::Graph;
+use rustc_data_structures::graph::{Graph, NodeIndex};
use super::hash::*;
use ich::Fingerprint;
// of the graph down.
pub reduced_graph: Graph<&'query DepNode<DefId>, ()>,
+ // These are output nodes that have no incoming edges. We have to
+ // track these specially because, when we load the data back up
+ // again, we want to make sure and recreate these nodes (we want
+ // to recreate the nodes where all incoming edges are clean; but
+ // since we ordinarily just serialize edges, we wind up just
+ // forgetting that bootstrap outputs even exist in that case.)
+ pub bootstrap_outputs: Vec<&'query DepNode<DefId>>,
+
// For the inputs (hir/foreign-metadata), we include hashes.
pub hashes: FxHashMap<&'query DepNode<DefId>, Fingerprint>,
}
// Reduce the graph to the most important nodes.
let compress::Reduction { graph, input_nodes } =
- compress::reduce_graph(&query.graph, HashContext::is_hashable, is_output);
+ compress::reduce_graph(&query.graph, HashContext::is_hashable, |n| is_output(n));
let mut hashes = FxHashMap();
for input_index in input_nodes {
.or_insert_with(|| hcx.hash(input).unwrap());
}
+ let bootstrap_outputs: Vec<&'q DepNode<DefId>> =
+ (0 .. graph.len_nodes())
+ .map(NodeIndex)
+ .filter(|&n| graph.incoming_edges(n).next().is_none())
+ .map(|n| *graph.node_data(n))
+ .filter(|n| is_output(n))
+ .collect();
+
Predecessors {
reduced_graph: graph,
+ bootstrap_outputs: bootstrap_outputs,
hashes: hashes,
}
}
}
// Create the serialized dep-graph.
+ let bootstrap_outputs = preds.bootstrap_outputs.iter()
+ .map(|n| builder.map(n))
+ .collect();
let edges = edges.into_iter()
.map(|(k, v)| SerializedEdgeSet { source: k, targets: v })
.collect();
let graph = SerializedDepGraph {
- edges: edges,
+ bootstrap_outputs,
+ edges,
hashes: preds.hashes
.iter()
.map(|(&dep_node, &hash)| {
};
if tcx.sess.opts.debugging_opts.incremental_info {
+ println!("incremental: {} nodes in reduced dep-graph", preds.reduced_graph.len_nodes());
println!("incremental: {} edges in serialized dep-graph", graph.edges.len());
println!("incremental: {} hashes in serialized dep-graph", graph.hashes.len());
}
pub fn method_context(cx: &LateContext, id: ast::NodeId, span: Span) -> MethodLateContext {
let def_id = cx.tcx.hir.local_def_id(id);
- match cx.tcx.associated_items.borrow().get(&def_id) {
+ match cx.tcx.maps.associated_item.borrow().get(&def_id) {
None => span_bug!(span, "missing method descriptor?!"),
Some(item) => {
match item.container {
}
_ => return,
};
- if def.has_dtor() {
+ if def.has_dtor(cx.tcx) {
return;
}
let parameter_environment = cx.tcx.empty_parameter_environment();
let node_id = tcx.hir.as_local_node_id(method.def_id).unwrap();
let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
- tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
let mut selcx = traits::SelectionContext::new(&infcx);
match selcx.select(&obligation) {
// The method comes from a `T: Trait` bound.
}
let typ = cx.tables.node_id_to_type(expr.id);
match typ.sty {
- ty::TyFnDef(.., ref bare_fn) if bare_fn.abi == RustIntrinsic => {
- let from = bare_fn.sig.skip_binder().inputs()[0];
- let to = bare_fn.sig.skip_binder().output();
+ ty::TyFnDef(.., bare_fn) if bare_fn.abi() == RustIntrinsic => {
+ let from = bare_fn.inputs().skip_binder()[0];
+ let to = *bare_fn.output().skip_binder();
return Some((&from.sty, &to.sty));
}
_ => (),
fn def_id_is_transmute(cx: &LateContext, def_id: DefId) -> bool {
match cx.tcx.item_type(def_id).sty {
- ty::TyFnDef(.., ref bfty) if bfty.abi == RustIntrinsic => (),
+ ty::TyFnDef(.., bfty) if bfty.abi() == RustIntrinsic => (),
_ => return false,
}
cx.tcx.item_name(def_id) == "transmute"
use rustc::traits::Reveal;
use middle::const_val::ConstVal;
use rustc_const_eval::ConstContext;
-use rustc_const_eval::EvalHint::ExprTypeChecked;
use util::nodemap::FxHashSet;
use lint::{LateContext, LintContext, LintArray};
use lint::{LintPass, LateLintPass};
}
} else {
let const_cx = ConstContext::with_tables(cx.tcx, cx.tables);
- match const_cx.eval(&r, ExprTypeChecked) {
+ match const_cx.eval(&r) {
Ok(ConstVal::Integral(i)) => {
i.is_negative() ||
i.to_u64()
false
}
+fn is_ffi_safe(ty: attr::IntType) -> bool {
+ match ty {
+ attr::SignedInt(ast::IntTy::I8) | attr::UnsignedInt(ast::UintTy::U8) |
+ attr::SignedInt(ast::IntTy::I16) | attr::UnsignedInt(ast::UintTy::U16) |
+ attr::SignedInt(ast::IntTy::I32) | attr::UnsignedInt(ast::UintTy::U32) |
+ attr::SignedInt(ast::IntTy::I64) | attr::UnsignedInt(ast::UintTy::U64) |
+ attr::SignedInt(ast::IntTy::I128) | attr::UnsignedInt(ast::UintTy::U128) => true,
+ attr::SignedInt(ast::IntTy::Is) | attr::UnsignedInt(ast::UintTy::Us) => false
+ }
+}
+
impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
/// Check if the given type is "ffi-safe" (has a stable, well-defined
/// representation which can be exported to C code).
}
match def.adt_kind() {
AdtKind::Struct => {
- if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+ if !def.repr.c {
return FfiUnsafe("found struct without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
if all_phantom { FfiPhantom } else { FfiSafe }
}
AdtKind::Union => {
- if !cx.lookup_repr_hints(def.did).contains(&attr::ReprExtern) {
+ if !def.repr.c {
return FfiUnsafe("found union without foreign-function-safe \
representation annotation in foreign module, \
consider adding a #[repr(C)] attribute to the type");
// Check for a repr() attribute to specify the size of the
// discriminant.
- let repr_hints = cx.lookup_repr_hints(def.did);
- match &repr_hints[..] {
- &[] => {
- // Special-case types like `Option<extern fn()>`.
- if !is_repr_nullable_ptr(cx, def, substs) {
- return FfiUnsafe("found enum without foreign-function-safe \
- representation annotation in foreign \
- module, consider adding a #[repr(...)] \
- attribute to the type");
- }
+ if !def.repr.c && def.repr.int.is_none() {
+ // Special-case types like `Option<extern fn()>`.
+ if !is_repr_nullable_ptr(cx, def, substs) {
+ return FfiUnsafe("found enum without foreign-function-safe \
+ representation annotation in foreign \
+ module, consider adding a #[repr(...)] \
+ attribute to the type");
}
- &[ref hint] => {
- if !hint.is_ffi_safe() {
- // FIXME: This shouldn't be reachable: we should check
- // this earlier.
- return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
- }
-
- // Enum with an explicitly sized discriminant; either
- // a C-style enum or a discriminated union.
+ }
- // The layout of enum variants is implicitly repr(C).
- // FIXME: Is that correct?
- }
- _ => {
+ if let Some(int_ty) = def.repr.int {
+ if !is_ffi_safe(int_ty) {
// FIXME: This shouldn't be reachable: we should check
// this earlier.
- return FfiUnsafe("enum has too many #[repr(...)] attributes");
+ return FfiUnsafe("enum has unexpected #[repr(...)] attribute");
}
+
+ // Enum with an explicitly sized discriminant; either
+ // a C-style enum or a discriminated union.
+
+ // The layout of enum variants is implicitly repr(C).
+ // FIXME: Is that correct?
}
// Check the contained variants.
ty::TyArray(ty, _) => self.check_type_for_ffi(cache, ty),
- ty::TyFnPtr(bare_fn) => {
- match bare_fn.abi {
+ ty::TyFnPtr(sig) => {
+ match sig.abi() {
Abi::Rust | Abi::RustIntrinsic | Abi::PlatformIntrinsic | Abi::RustCall => {
return FfiUnsafe("found function pointer with Rust calling convention in \
foreign module; consider using an `extern` function \
_ => {}
}
- let sig = cx.erase_late_bound_regions(&bare_fn.sig);
+ let sig = cx.erase_late_bound_regions(&sig);
if !sig.output().is_nil() {
let r = self.check_type_for_ffi(cache, sig.output());
match r {
let mut found = false;
for lib in self.cstore.get_used_libraries().borrow_mut().iter_mut() {
if lib.name == name as &str {
- lib.kind = kind;
+ let mut changed = false;
+ if let Some(k) = kind {
+ lib.kind = k;
+ changed = true;
+ }
if let &Some(ref new_name) = new_name {
lib.name = Symbol::intern(new_name);
+ changed = true;
+ }
+ if !changed {
+ self.sess.warn(&format!("redundant linker flag specified for library `{}`",
+ name));
}
+
found = true;
}
}
let new_name = new_name.as_ref().map(|s| &**s); // &Option<String> -> Option<&str>
let lib = NativeLibrary {
name: Symbol::intern(new_name.unwrap_or(name)),
- kind: kind,
+ kind: if let Some(k) = kind { k } else { cstore::NativeUnknown },
cfg: None,
foreign_items: Vec::new(),
};
pub use rustc::middle::cstore::NativeLibraryKind::*;
pub use rustc::middle::cstore::{CrateSource, LinkMeta, LibSource};
+pub use cstore_impl::provide;
+
// A map from external crate numbers (as decoded from some crate file) to
// local crate numbers (as generated during this session). Each external
// crate may refer to types in other external crates, and each has their
use locator;
use schema;
+use rustc::dep_graph::DepTrackingMapConfig;
use rustc::middle::cstore::{CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
use rustc::middle::cstore::{NativeLibrary, LinkMeta, LinkagePreference, LoadedMacro};
use rustc::hir::def::{self, Def};
use rustc::middle::lang_items;
-use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
use rustc::session::Session;
-use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::{self, TyCtxt};
+use rustc::ty::maps::Providers;
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::dep_graph::DepNode;
use rustc::hir::map::{DefKey, DefPath, DisambiguatedDefPathData};
-use rustc::mir::Mir;
use rustc::util::nodemap::{NodeSet, DefIdMap};
use rustc_back::PanicStrategy;
+use std::any::Any;
+use std::mem;
+use std::rc::Rc;
+
use syntax::ast;
use syntax::attr;
use syntax::parse::filemap_to_tts;
use std::collections::BTreeMap;
-impl<'tcx> CrateStore<'tcx> for cstore::CStore {
- fn describe_def(&self, def: DefId) -> Option<Def> {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_def(def.index)
- }
-
- fn def_span(&self, sess: &Session, def: DefId) -> Span {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_span(def.index, sess)
- }
-
- fn stability(&self, def: DefId) -> Option<attr::Stability> {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_stability(def.index)
+macro_rules! provide {
+ (<$lt:tt> $tcx:ident, $def_id:ident, $cdata:ident $($name:ident => $compute:block)*) => {
+ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
+ $(fn $name<'a, $lt:$lt>($tcx: TyCtxt<'a, $lt, $lt>, $def_id: DefId)
+ -> <ty::queries::$name<$lt> as
+ DepTrackingMapConfig>::Value {
+ assert!(!$def_id.is_local());
+
+ $tcx.dep_graph.read(DepNode::MetaData($def_id));
+
+ let $cdata = $tcx.sess.cstore.crate_data_as_rc_any($def_id.krate);
+ let $cdata = $cdata.downcast_ref::<cstore::CrateMetadata>()
+ .expect("CrateStore crated ata is not a CrateMetadata");
+ $compute
+ })*
+
+ *providers = Providers {
+ $($name,)*
+ ..*providers
+ };
+ }
}
+}
- fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_deprecation(def.index)
+provide! { <'tcx> tcx, def_id, cdata
+ ty => { cdata.get_type(def_id.index, tcx) }
+ generics => { tcx.alloc_generics(cdata.get_generics(def_id.index)) }
+ predicates => { cdata.get_predicates(def_id.index, tcx) }
+ super_predicates => { cdata.get_super_predicates(def_id.index, tcx) }
+ trait_def => {
+ tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx))
+ }
+ adt_def => { cdata.get_adt_def(def_id.index, tcx) }
+ variances => { Rc::new(cdata.get_item_variances(def_id.index)) }
+ associated_item_def_ids => {
+ let mut result = vec![];
+ cdata.each_child_of_item(def_id.index, |child| result.push(child.def.def_id()));
+ Rc::new(result)
+ }
+ associated_item => { cdata.get_associated_item(def_id.index) }
+ impl_trait_ref => { cdata.get_impl_trait(def_id.index, tcx) }
+ custom_coerce_unsized_kind => {
+ cdata.get_custom_coerce_unsized_kind(def_id.index).unwrap_or_else(|| {
+ bug!("custom_coerce_unsized_kind: `{:?}` is missing its kind", def_id);
+ })
}
+ mir => {
+ let mir = cdata.maybe_get_item_mir(tcx, def_id.index).unwrap_or_else(|| {
+ bug!("get_item_mir: missing MIR for `{:?}`", def_id)
+ });
- fn visibility(&self, def: DefId) -> ty::Visibility {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_visibility(def.index)
- }
+ let mir = tcx.alloc_mir(mir);
- fn closure_kind(&self, def_id: DefId) -> ty::ClosureKind
- {
- assert!(!def_id.is_local());
- self.dep_graph.read(DepNode::MetaData(def_id));
- self.get_crate_data(def_id.krate).closure_kind(def_id.index)
- }
+ // Perma-borrow MIR from extern crates to prevent mutation.
+ mem::forget(mir.borrow());
- fn closure_ty<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> ty::ClosureTy<'tcx> {
- assert!(!def_id.is_local());
- self.dep_graph.read(DepNode::MetaData(def_id));
- self.get_crate_data(def_id.krate).closure_ty(def_id.index, tcx)
+ mir
}
+ mir_const_qualif => { cdata.mir_const_qualif(def_id.index) }
+ typeck_tables => { cdata.item_body_tables(def_id.index, tcx) }
+ closure_kind => { cdata.closure_kind(def_id.index) }
+ closure_type => { cdata.closure_ty(def_id.index, tcx) }
+}
- fn item_variances(&self, def: DefId) -> Vec<ty::Variance> {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_item_variances(def.index)
+impl CrateStore for cstore::CStore {
+ fn crate_data_as_rc_any(&self, krate: CrateNum) -> Rc<Any> {
+ self.get_crate_data(krate)
}
- fn item_type<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Ty<'tcx>
- {
+ fn describe_def(&self, def: DefId) -> Option<Def> {
self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_type(def.index, tcx)
+ self.get_crate_data(def.krate).get_def(def.index)
}
- fn item_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> ty::GenericPredicates<'tcx>
- {
+ fn def_span(&self, sess: &Session, def: DefId) -> Span {
self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_predicates(def.index, tcx)
+ self.get_crate_data(def.krate).get_span(def.index, sess)
}
- fn item_super_predicates<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> ty::GenericPredicates<'tcx>
- {
+ fn stability(&self, def: DefId) -> Option<attr::Stability> {
self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_super_predicates(def.index, tcx)
+ self.get_crate_data(def.krate).get_stability(def.index)
}
- fn item_generics<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> ty::Generics<'tcx>
- {
+ fn deprecation(&self, def: DefId) -> Option<attr::Deprecation> {
self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_generics(def.index, tcx)
+ self.get_crate_data(def.krate).get_deprecation(def.index)
}
- fn item_generics_own_param_counts(&self, def: DefId) -> (usize, usize) {
+ fn visibility(&self, def: DefId) -> ty::Visibility {
self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).generics_own_param_counts(def.index)
+ self.get_crate_data(def.krate).get_visibility(def.index)
}
- fn item_generics_object_lifetime_defaults(&self, def: DefId)
- -> Vec<ObjectLifetimeDefault> {
+ fn item_generics_cloned(&self, def: DefId) -> ty::Generics {
self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).generics_object_lifetime_defaults(def.index)
+ self.get_crate_data(def.krate).get_generics(def.index)
}
fn item_attrs(&self, def_id: DefId) -> Vec<ast::Attribute>
self.get_crate_data(def_id.krate).get_item_attrs(def_id.index)
}
- fn trait_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> ty::TraitDef
- {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_trait_def(def.index, tcx)
- }
-
- fn adt_def<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> &'tcx ty::AdtDef
- {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_adt_def(def.index, tcx)
- }
-
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
{
// FIXME(#38501) We've skipped a `read` on the `HirBody` of
result
}
- fn associated_item_def_ids(&self, def_id: DefId) -> Vec<DefId> {
- self.dep_graph.read(DepNode::MetaData(def_id));
- let mut result = vec![];
- self.get_crate_data(def_id.krate)
- .each_child_of_item(def_id.index, |child| result.push(child.def.def_id()));
- result
- }
-
fn impl_polarity(&self, def: DefId) -> hir::ImplPolarity
{
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).get_impl_polarity(def.index)
}
- fn impl_trait_ref<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<ty::TraitRef<'tcx>>
- {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_impl_trait(def.index, tcx)
- }
-
- fn custom_coerce_unsized_kind(&self, def: DefId)
- -> Option<ty::adjustment::CustomCoerceUnsized>
- {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).get_custom_coerce_unsized_kind(def.index)
- }
-
fn impl_parent(&self, impl_def: DefId) -> Option<DefId> {
self.dep_graph.read(DepNode::MetaData(impl_def));
self.get_crate_data(impl_def.krate).get_parent_impl(impl_def.index)
self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index)
}
- fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>
+ fn associated_item_cloned(&self, def: DefId) -> ty::AssociatedItem
{
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).get_associated_item(def.index)
self.get_crate_data(did.krate).is_const_fn(did.index)
}
- fn is_defaulted_trait(&self, trait_def_id: DefId) -> bool
- {
- self.dep_graph.read(DepNode::MetaData(trait_def_id));
- self.get_crate_data(trait_def_id.krate).is_defaulted_trait(trait_def_id.index)
- }
-
fn is_default_impl(&self, impl_did: DefId) -> bool {
self.dep_graph.read(DepNode::MetaData(impl_did));
self.get_crate_data(impl_did.krate).is_default_impl(impl_did.index)
})
}
- fn maybe_get_item_body<'a>(&'tcx self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId)
- -> Option<&'tcx hir::Body>
+ fn maybe_get_item_body<'a, 'tcx>(&self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> Option<&'tcx hir::Body>
{
if let Some(cached) = tcx.hir.get_inlined_body(def_id) {
return Some(cached);
self.get_crate_data(def.krate).const_is_rvalue_promotable_to_static(def.index)
}
- fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId) -> Mir<'tcx> {
- self.dep_graph.read(DepNode::MetaData(def));
- self.get_crate_data(def.krate).maybe_get_item_mir(tcx, def.index).unwrap_or_else(|| {
- bug!("get_item_mir: missing MIR for {}", tcx.item_path_str(def))
- })
- }
-
fn is_item_mir_available(&self, def: DefId) -> bool {
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).is_item_mir_available(def.index)
self.do_extern_mod_stmt_cnum(emod_id)
}
- fn encode_metadata<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
- reexports: &def::ExportMap,
- link_meta: &LinkMeta,
- reachable: &NodeSet) -> Vec<u8>
+ fn encode_metadata<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ reexports: &def::ExportMap,
+ link_meta: &LinkMeta,
+ reachable: &NodeSet) -> Vec<u8>
{
encoder::encode_metadata(tcx, self, reexports, link_meta, reachable)
}
use rustc::hir::def::{self, Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc::middle::lang_items;
-use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use syntax::attr;
use syntax::ast;
use syntax::codemap;
+use syntax::ext::base::MacroKind;
use syntax_pos::{self, Span, BytePos, Pos, DUMMY_SP};
pub struct DecodeContext<'a, 'tcx: 'a> {
}
}
-impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::BareFnTy<'tcx>> for DecodeContext<'a, 'tcx> {
- fn specialized_decode(&mut self) -> Result<&'tcx ty::BareFnTy<'tcx>, Self::Error> {
- Ok(self.tcx().mk_bare_fn(Decodable::decode(self)?))
- }
-}
-
impl<'a, 'tcx> SpecializedDecoder<&'tcx ty::AdtDef> for DecodeContext<'a, 'tcx> {
fn specialized_decode(&mut self) -> Result<&'tcx ty::AdtDef, Self::Error> {
let def_id = DefId::decode(self)?;
impl<'tcx> EntryKind<'tcx> {
fn to_def(&self, did: DefId) -> Option<Def> {
Some(match *self {
- EntryKind::Const => Def::Const(did),
- EntryKind::AssociatedConst(_) => Def::AssociatedConst(did),
+ EntryKind::Const(_) => Def::Const(did),
+ EntryKind::AssociatedConst(..) => Def::AssociatedConst(did),
EntryKind::ImmStatic |
EntryKind::ForeignImmStatic => Def::Static(did, false),
EntryKind::MutStatic |
EntryKind::Variant(_) => Def::Variant(did),
EntryKind::Trait(_) => Def::Trait(did),
EntryKind::Enum(..) => Def::Enum(did),
- EntryKind::MacroDef(_) => Def::Macro(did),
+ EntryKind::MacroDef(_) => Def::Macro(did, MacroKind::Bang),
EntryKind::ForeignMod |
EntryKind::Impl(_) |
}
pub fn get_def(&self, index: DefIndex) -> Option<Def> {
- match self.is_proc_macro(index) {
- true => Some(Def::Macro(self.local_def_id(index))),
- false => self.entry(index).kind.to_def(self.local_def_id(index)),
+ if !self.is_proc_macro(index) {
+ self.entry(index).kind.to_def(self.local_def_id(index))
+ } else {
+ let kind = self.proc_macros.as_ref().unwrap()[index.as_usize() - 1].1.kind();
+ Some(Def::Macro(self.local_def_id(index), kind))
}
}
_ => bug!(),
};
- ty::TraitDef::new(self.local_def_id(item_id),
- data.unsafety,
- data.paren_sugar,
- self.def_path(item_id).deterministic_hash(tcx))
+ let def = ty::TraitDef::new(self.local_def_id(item_id),
+ data.unsafety,
+ data.paren_sugar,
+ self.def_path(item_id).deterministic_hash(tcx));
+
+ if data.has_default_impl {
+ def.record_has_default_impl();
+ }
+
+ def
}
fn get_variant(&self,
item: &Entry<'tcx>,
- index: DefIndex)
+ index: DefIndex,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>)
-> (ty::VariantDef, Option<DefIndex>) {
let data = match item.kind {
EntryKind::Variant(data) |
_ => bug!(),
};
+ if let ty::VariantDiscr::Explicit(def_id) = data.discr {
+ let result = data.evaluated_discr.map_or(Err(()), Ok);
+ tcx.maps.monomorphic_const_eval.borrow_mut().insert(def_id, result);
+ }
+
(ty::VariantDef {
did: self.local_def_id(data.struct_ctor.unwrap_or(index)),
name: self.item_name(index),
vis: f.visibility.decode(self)
}
}).collect(),
- disr_val: data.disr,
+ discr: data.discr,
ctor_kind: data.ctor_kind,
}, data.struct_ctor)
}
-> &'tcx ty::AdtDef {
let item = self.entry(item_id);
let did = self.local_def_id(item_id);
- let (kind, ty) = match item.kind {
- EntryKind::Enum(dt, _) => (ty::AdtKind::Enum, Some(dt.decode(self))),
- EntryKind::Struct(_, _) => (ty::AdtKind::Struct, None),
- EntryKind::Union(_, _) => (ty::AdtKind::Union, None),
+ let kind = match item.kind {
+ EntryKind::Enum(_) => ty::AdtKind::Enum,
+ EntryKind::Struct(_, _) => ty::AdtKind::Struct,
+ EntryKind::Union(_, _) => ty::AdtKind::Union,
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
};
let mut ctor_index = None;
item.children
.decode(self)
.map(|index| {
- let (variant, struct_ctor) = self.get_variant(&self.entry(index), index);
+ let (variant, struct_ctor) =
+ self.get_variant(&self.entry(index), index, tcx);
assert_eq!(struct_ctor, None);
variant
})
.collect()
} else {
- let (variant, struct_ctor) = self.get_variant(&item, item_id);
+ let (variant, struct_ctor) = self.get_variant(&item, item_id, tcx);
ctor_index = struct_ctor;
vec![variant]
};
let (kind, repr) = match item.kind {
- EntryKind::Enum(_, repr) => (ty::AdtKind::Enum, repr),
+ EntryKind::Enum(repr) => (ty::AdtKind::Enum, repr),
EntryKind::Struct(_, repr) => (ty::AdtKind::Struct, repr),
EntryKind::Union(_, repr) => (ty::AdtKind::Union, repr),
_ => bug!("get_adt_def called on a non-ADT {:?}", did),
};
- let adt = tcx.alloc_adt_def(did, kind, ty, variants, repr);
+ let adt = tcx.alloc_adt_def(did, kind, variants, repr);
if let Some(ctor_index) = ctor_index {
// Make adt definition available through constructor id as well.
- tcx.adt_defs.borrow_mut().insert(self.local_def_id(ctor_index), adt);
+ tcx.maps.adt_def.borrow_mut().insert(self.local_def_id(ctor_index), adt);
}
adt
}
}
- pub fn get_generics(&self,
- item_id: DefIndex,
- tcx: TyCtxt<'a, 'tcx, 'tcx>)
- -> ty::Generics<'tcx> {
- let g = self.entry(item_id).generics.unwrap().decode(self);
- ty::Generics {
- parent: g.parent,
- parent_regions: g.parent_regions,
- parent_types: g.parent_types,
- regions: g.regions.decode((self, tcx)).collect(),
- types: g.types.decode((self, tcx)).collect(),
- has_self: g.has_self,
- }
- }
-
- pub fn generics_own_param_counts(&self, item_id: DefIndex) -> (usize, usize) {
- let g = self.entry(item_id).generics.unwrap().decode(self);
- (g.regions.len, g.types.len)
- }
-
- pub fn generics_object_lifetime_defaults(&self, item_id: DefIndex)
- -> Vec<ObjectLifetimeDefault> {
+ pub fn get_generics(&self, item_id: DefIndex) -> ty::Generics {
self.entry(item_id).generics.unwrap().decode(self)
- .object_lifetime_defaults.decode(self).collect()
}
pub fn get_type(&self, id: DefIndex, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Ty<'tcx> {
{
if let Some(ref proc_macros) = self.proc_macros {
if id == CRATE_DEF_INDEX {
- for (id, &(name, _)) in proc_macros.iter().enumerate() {
- let def = Def::Macro(DefId { krate: self.cnum, index: DefIndex::new(id + 1) });
+ for (id, &(name, ref ext)) in proc_macros.iter().enumerate() {
+ let def = Def::Macro(
+ DefId {
+ krate: self.cnum,
+ index: DefIndex::new(id + 1)
+ },
+ ext.kind()
+ );
callback(def::Export { name: name, def: def });
}
}
if self.is_proc_macro(id) { return None; }
self.entry(id).ast.map(|ast| {
let def_id = self.local_def_id(id);
- let ast = ast.decode(self);
-
- let tables = ast.tables.decode((self, tcx));
- tcx.tables.borrow_mut().insert(def_id, tcx.alloc_tables(tables));
-
- let body = ast.body.decode((self, tcx));
+ let body = ast.decode(self).body.decode(self);
tcx.hir.intern_inlined_body(def_id, body)
})
}
+ pub fn item_body_tables(&self,
+ id: DefIndex,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>)
+ -> &'tcx ty::TypeckTables<'tcx> {
+ let ast = self.entry(id).ast.unwrap().decode(self);
+ tcx.alloc_tables(ast.tables.decode((self, tcx)))
+ }
+
pub fn item_body_nested_bodies(&self, id: DefIndex) -> BTreeMap<hir::BodyId, hir::Body> {
self.entry(id).ast.into_iter().flat_map(|ast| {
ast.decode(self).nested_bodies.decode(self).map(|body| (body.id(), body))
}
}
- pub fn get_associated_item(&self, id: DefIndex) -> Option<ty::AssociatedItem> {
+ pub fn mir_const_qualif(&self, id: DefIndex) -> u8 {
+ match self.entry(id).kind {
+ EntryKind::Const(qualif) |
+ EntryKind::AssociatedConst(AssociatedContainer::ImplDefault, qualif) |
+ EntryKind::AssociatedConst(AssociatedContainer::ImplFinal, qualif) => {
+ qualif
+ }
+ _ => bug!(),
+ }
+ }
+
+ pub fn get_associated_item(&self, id: DefIndex) -> ty::AssociatedItem {
let item = self.entry(id);
- let parent_and_name = || {
- let def_key = self.def_key(id);
- (self.local_def_id(def_key.parent.unwrap()),
- def_key.disambiguated_data.data.get_opt_name().unwrap())
- };
+ let def_key = self.def_key(id);
+ let parent = self.local_def_id(def_key.parent.unwrap());
+ let name = def_key.disambiguated_data.data.get_opt_name().unwrap();
- Some(match item.kind {
- EntryKind::AssociatedConst(container) => {
- let (parent, name) = parent_and_name();
- ty::AssociatedItem {
- name: name,
- kind: ty::AssociatedKind::Const,
- vis: item.visibility.decode(self),
- defaultness: container.defaultness(),
- def_id: self.local_def_id(id),
- container: container.with_def_id(parent),
- method_has_self_argument: false
- }
+ let (kind, container, has_self) = match item.kind {
+ EntryKind::AssociatedConst(container, _) => {
+ (ty::AssociatedKind::Const, container, false)
}
EntryKind::Method(data) => {
- let (parent, name) = parent_and_name();
let data = data.decode(self);
- ty::AssociatedItem {
- name: name,
- kind: ty::AssociatedKind::Method,
- vis: item.visibility.decode(self),
- defaultness: data.container.defaultness(),
- def_id: self.local_def_id(id),
- container: data.container.with_def_id(parent),
- method_has_self_argument: data.has_self
- }
+ (ty::AssociatedKind::Method, data.container, data.has_self)
}
EntryKind::AssociatedType(container) => {
- let (parent, name) = parent_and_name();
- ty::AssociatedItem {
- name: name,
- kind: ty::AssociatedKind::Type,
- vis: item.visibility.decode(self),
- defaultness: container.defaultness(),
- def_id: self.local_def_id(id),
- container: container.with_def_id(parent),
- method_has_self_argument: false
- }
+ (ty::AssociatedKind::Type, container, false)
}
- _ => return None,
- })
+ _ => bug!()
+ };
+
+ ty::AssociatedItem {
+ name: name,
+ kind: kind,
+ vis: item.visibility.decode(self),
+ defaultness: container.defaultness(),
+ def_id: self.local_def_id(id),
+ container: container.with_def_id(parent),
+ method_has_self_argument: has_self
+ }
}
pub fn get_item_variances(&self, id: DefIndex) -> Vec<ty::Variance> {
self.dllimport_foreign_items.contains(&id)
}
- pub fn is_defaulted_trait(&self, trait_id: DefIndex) -> bool {
- match self.entry(trait_id).kind {
- EntryKind::Trait(data) => data.decode(self).has_default_impl,
- _ => bug!(),
- }
- }
-
pub fn is_default_impl(&self, impl_id: DefIndex) -> bool {
match self.entry(impl_id).kind {
EntryKind::DefaultImpl(_) => true,
pub fn closure_ty(&self,
closure_id: DefIndex,
tcx: TyCtxt<'a, 'tcx, 'tcx>)
- -> ty::ClosureTy<'tcx> {
+ -> ty::PolyFnSig<'tcx> {
match self.entry(closure_id).kind {
EntryKind::Closure(data) => data.decode(self).ty.decode((self, tcx)),
_ => bug!(),
use syntax::codemap::Spanned;
use syntax::attr;
use syntax::symbol::Symbol;
-use syntax_pos;
+use syntax_pos::{self, DUMMY_SP};
use rustc::hir::{self, PatKind};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
let data = VariantData {
ctor_kind: variant.ctor_kind,
- disr: variant.disr_val,
+ discr: variant.discr,
+ evaluated_discr: match variant.discr {
+ ty::VariantDiscr::Explicit(def_id) => {
+ ty::queries::monomorphic_const_eval::get(tcx, DUMMY_SP, def_id).ok()
+ }
+ ty::VariantDiscr::Relative(_) => None
+ },
struct_ctor: None,
};
let data = VariantData {
ctor_kind: variant.ctor_kind,
- disr: variant.disr_val,
+ discr: variant.discr,
+ evaluated_discr: None,
struct_ctor: Some(def_id.index),
};
}
}
- fn encode_generics(&mut self, def_id: DefId) -> Lazy<Generics<'tcx>> {
+ fn encode_generics(&mut self, def_id: DefId) -> Lazy<ty::Generics> {
let tcx = self.tcx;
- let g = tcx.item_generics(def_id);
- let regions = self.lazy_seq_ref(&g.regions);
- let types = self.lazy_seq_ref(&g.types);
- let mut object_lifetime_defaults = LazySeq::empty();
- if let Some(id) = tcx.hir.as_local_node_id(def_id) {
- if let Some(o) = tcx.named_region_map.object_lifetime_defaults.get(&id) {
- object_lifetime_defaults = self.lazy_seq_ref(o);
- }
- }
- self.lazy(&Generics {
- parent: g.parent,
- parent_regions: g.parent_regions,
- parent_types: g.parent_types,
- regions: regions,
- types: types,
- has_self: g.has_self,
- object_lifetime_defaults: object_lifetime_defaults,
- })
+ self.lazy(tcx.item_generics(def_id))
}
fn encode_predicates(&mut self, def_id: DefId) -> Lazy<ty::GenericPredicates<'tcx>> {
};
let kind = match trait_item.kind {
- ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
+ ty::AssociatedKind::Const => {
+ EntryKind::AssociatedConst(container, 0)
+ }
ty::AssociatedKind::Method => {
let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
let arg_names = match *m {
};
let kind = match impl_item.kind {
- ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
+ ty::AssociatedKind::Const => {
+ EntryKind::AssociatedConst(container,
+ ty::queries::mir_const_qualif::get(self.tcx, ast_item.span, def_id))
+ }
ty::AssociatedKind::Method => {
let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
FnData {
}
fn encode_mir(&mut self, def_id: DefId) -> Option<Lazy<mir::Mir<'tcx>>> {
- self.tcx.mir_map.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
+ self.tcx.maps.mir.borrow().get(&def_id).map(|mir| self.lazy(&*mir.borrow()))
}
// Encodes the inherent implementations of a structure, enumeration, or trait.
fn encode_inherent_implementations(&mut self, def_id: DefId) -> LazySeq<DefIndex> {
- match self.tcx.inherent_impls.borrow().get(&def_id) {
+ match self.tcx.maps.inherent_impls.borrow().get(&def_id) {
None => LazySeq::empty(),
Some(implementations) => {
self.lazy_seq(implementations.iter().map(|&def_id| {
let kind = match item.node {
hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
- hir::ItemConst(..) => EntryKind::Const,
+ hir::ItemConst(..) => {
+ EntryKind::Const(ty::queries::mir_const_qualif::get(tcx, item.span, def_id))
+ }
hir::ItemFn(_, _, constness, .., body) => {
let data = FnData {
constness: constness,
}
hir::ItemForeignMod(_) => EntryKind::ForeignMod,
hir::ItemTy(..) => EntryKind::Type,
- hir::ItemEnum(..) => EntryKind::Enum(self.lazy(&tcx.lookup_adt_def(def_id).discr_ty),
- get_repr_options(&tcx, def_id)),
+ hir::ItemEnum(..) => EntryKind::Enum(get_repr_options(&tcx, def_id)),
hir::ItemStruct(ref struct_def, _) => {
let variant = tcx.lookup_adt_def(def_id).struct_variant();
EntryKind::Struct(self.lazy(&VariantData {
ctor_kind: variant.ctor_kind,
- disr: variant.disr_val,
+ discr: variant.discr,
+ evaluated_discr: None,
struct_ctor: struct_ctor,
}), repr_options)
}
EntryKind::Union(self.lazy(&VariantData {
ctor_kind: variant.ctor_kind,
- disr: variant.disr_val,
+ discr: variant.discr,
+ evaluated_discr: None,
struct_ctor: None,
}), repr_options)
}
let data = ImplData {
polarity: polarity,
parent_impl: parent,
- coerce_unsized_kind: tcx.custom_coerce_unsized_kinds
+ coerce_unsized_kind: tcx.maps.custom_coerce_unsized_kind
.borrow()
.get(&def_id)
.cloned(),
EncodeContext::encode_info_for_foreign_item,
(def_id, ni));
}
+ fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
+ intravisit::walk_generics(self, generics);
+ self.index.encode_info_for_generics(generics);
+ }
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
intravisit::walk_ty(self, ty);
self.index.encode_info_for_ty(ty);
}
impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
+ fn encode_info_for_generics(&mut self, generics: &hir::Generics) {
+ for ty_param in &generics.ty_params {
+ let def_id = self.tcx.hir.local_def_id(ty_param.id);
+ let has_default = Untracked(ty_param.default.is_some());
+ self.record(def_id, EncodeContext::encode_info_for_ty_param, (def_id, has_default));
+ }
+ }
+
fn encode_info_for_ty(&mut self, ty: &hir::Ty) {
if let hir::TyImplTrait(_) = ty.node {
let def_id = self.tcx.hir.local_def_id(ty.id);
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
+ fn encode_info_for_ty_param(&mut self,
+ (def_id, Untracked(has_default)): (DefId, Untracked<bool>))
+ -> Entry<'tcx> {
+ let tcx = self.tcx;
+ Entry {
+ kind: EntryKind::Type,
+ visibility: self.lazy(&ty::Visibility::Public),
+ span: self.lazy(&tcx.def_span(def_id)),
+ attributes: LazySeq::empty(),
+ children: LazySeq::empty(),
+ stability: None,
+ deprecation: None,
+
+ ty: if has_default {
+ Some(self.encode_item_type(def_id))
+ } else {
+ None
+ },
+ inherent_impls: LazySeq::empty(),
+ variances: LazySeq::empty(),
+ generics: None,
+ predicates: None,
+
+ ast: None,
+ mir: None,
+ }
+ }
+
fn encode_info_for_anon_ty(&mut self, def_id: DefId) -> Entry<'tcx> {
let tcx = self.tcx;
Entry {
let data = ClosureData {
kind: tcx.closure_kind(def_id),
- ty: self.lazy(&tcx.closure_tys.borrow()[&def_id]),
+ ty: self.lazy(&tcx.closure_type(def_id)),
};
Entry {
#![feature(box_patterns)]
#![feature(conservative_impl_trait)]
#![feature(core_intrinsics)]
+#![cfg_attr(stage0, feature(field_init_shorthand))]
#![feature(i128_type)]
#![feature(proc_macro_internals)]
#![feature(quote)]
use rustc::hir;
use rustc::hir::def::{self, CtorKind};
use rustc::hir::def_id::{DefIndex, DefId};
+use rustc::middle::const_val::ConstVal;
use rustc::middle::cstore::{DepKind, LinkagePreference, NativeLibrary};
use rustc::middle::lang_items;
-use rustc::middle::resolve_lifetime::ObjectLifetimeDefault;
use rustc::mir;
use rustc::ty::{self, Ty, ReprOptions};
use rustc_back::PanicStrategy;
pub ty: Option<Lazy<Ty<'tcx>>>,
pub inherent_impls: LazySeq<DefIndex>,
pub variances: LazySeq<ty::Variance>,
- pub generics: Option<Lazy<Generics<'tcx>>>,
+ pub generics: Option<Lazy<ty::Generics>>,
pub predicates: Option<Lazy<ty::GenericPredicates<'tcx>>>,
pub ast: Option<Lazy<astencode::Ast<'tcx>>>,
#[derive(Copy, Clone, RustcEncodable, RustcDecodable)]
pub enum EntryKind<'tcx> {
- Const,
+ Const(u8),
ImmStatic,
MutStatic,
ForeignImmStatic,
ForeignMutStatic,
ForeignMod,
Type,
- Enum(Lazy<attr::IntType>, ReprOptions),
+ Enum(ReprOptions),
Field,
- Variant(Lazy<VariantData>),
- Struct(Lazy<VariantData>, ReprOptions),
- Union(Lazy<VariantData>, ReprOptions),
+ Variant(Lazy<VariantData<'tcx>>),
+ Struct(Lazy<VariantData<'tcx>>, ReprOptions),
+ Union(Lazy<VariantData<'tcx>>, ReprOptions),
Fn(Lazy<FnData>),
ForeignFn(Lazy<FnData>),
Mod(Lazy<ModData>),
DefaultImpl(Lazy<ImplData<'tcx>>),
Method(Lazy<MethodData>),
AssociatedType(AssociatedContainer),
- AssociatedConst(AssociatedContainer),
-}
-
-/// A copy of `ty::Generics` which allows lazy decoding of
-/// `regions` and `types` (e.g. knowing the number of type
-/// and lifetime parameters before `TyCtxt` is created).
-#[derive(RustcEncodable, RustcDecodable)]
-pub struct Generics<'tcx> {
- pub parent: Option<DefId>,
- pub parent_regions: u32,
- pub parent_types: u32,
- pub regions: LazySeq<ty::RegionParameterDef>,
- pub types: LazySeq<ty::TypeParameterDef<'tcx>>,
- pub has_self: bool,
- pub object_lifetime_defaults: LazySeq<ObjectLifetimeDefault>,
+ AssociatedConst(AssociatedContainer, u8),
}
#[derive(RustcEncodable, RustcDecodable)]
}
#[derive(RustcEncodable, RustcDecodable)]
-pub struct VariantData {
+pub struct VariantData<'tcx> {
pub ctor_kind: CtorKind,
- pub disr: u128,
+ pub discr: ty::VariantDiscr,
+ pub evaluated_discr: Option<ConstVal<'tcx>>,
/// If this is a struct's only variant, this
/// is the index of the "struct ctor" item.
#[derive(RustcEncodable, RustcDecodable)]
pub struct ClosureData<'tcx> {
pub kind: ty::ClosureKind,
- pub ty: Lazy<ty::ClosureTy<'tcx>>,
+ pub ty: Lazy<ty::PolyFnSig<'tcx>>,
}
ExprKind::Use { .. } |
ExprKind::NeverToAny { .. } |
ExprKind::ReifyFnPointer { .. } |
+ ExprKind::ClosureFnPointer { .. } |
ExprKind::UnsafeFnPointer { .. } |
ExprKind::Unsize { .. } |
ExprKind::Repeat { .. } |
let source = unpack!(block = this.as_operand(block, source));
block.and(Rvalue::Cast(CastKind::UnsafeFnPointer, source, expr.ty))
}
+ ExprKind::ClosureFnPointer { source } => {
+ let source = unpack!(block = this.as_operand(block, source));
+ block.and(Rvalue::Cast(CastKind::ClosureFnPointer, source, expr.ty))
+ }
ExprKind::Unsize { source } => {
let source = unpack!(block = this.as_operand(block, source));
block.and(Rvalue::Cast(CastKind::Unsize, source, expr.ty))
ExprKind::Cast { .. } |
ExprKind::Use { .. } |
ExprKind::ReifyFnPointer { .. } |
+ ExprKind::ClosureFnPointer { .. } |
ExprKind::UnsafeFnPointer { .. } |
ExprKind::Unsize { .. } |
ExprKind::Repeat { .. } |
let diverges = match ty.sty {
ty::TyFnDef(_, _, ref f) | ty::TyFnPtr(ref f) => {
// FIXME(canndrew): This is_never should probably be an is_uninhabited
- f.sig.skip_binder().output().is_never()
+ f.output().skip_binder().is_never()
}
_ => false
};
ExprKind::Cast { .. } |
ExprKind::Use { .. } |
ExprKind::ReifyFnPointer { .. } |
+ ExprKind::ClosureFnPointer { .. } |
ExprKind::UnsafeFnPointer { .. } |
ExprKind::Unsize { .. } |
ExprKind::Repeat { .. } |
// test the branches of enum
SwitchInt {
switch_ty: Ty<'tcx>,
- options: Vec<ConstVal>,
- indices: FxHashMap<ConstVal, usize>,
+ options: Vec<ConstVal<'tcx>>,
+ indices: FxHashMap<ConstVal<'tcx>, usize>,
},
// test for equality
Eq {
- value: ConstVal,
+ value: ConstVal<'tcx>,
ty: Ty<'tcx>,
},
use hair::*;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::bitvec::BitVector;
-use rustc::middle::const_val::{ConstVal, ConstInt};
+use rustc::middle::const_val::ConstVal;
use rustc::ty::{self, Ty};
use rustc::ty::util::IntTypeExt;
use rustc::mir::*;
test_lvalue: &Lvalue<'tcx>,
candidate: &Candidate<'pat, 'tcx>,
switch_ty: Ty<'tcx>,
- options: &mut Vec<ConstVal>,
- indices: &mut FxHashMap<ConstVal, usize>)
+ options: &mut Vec<ConstVal<'tcx>>,
+ indices: &mut FxHashMap<ConstVal<'tcx>, usize>)
-> bool
{
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
let mut targets = Vec::with_capacity(used_variants + 1);
let mut values = Vec::with_capacity(used_variants);
let tcx = self.hir.tcx();
- for (idx, variant) in adt_def.variants.iter().enumerate() {
+ for (idx, discr) in adt_def.discriminants(tcx).enumerate() {
target_blocks.place_back() <- if variants.contains(idx) {
- let discr = ConstInt::new_inttype(variant.disr_val, adt_def.discr_ty,
- tcx.sess.target.uint_type,
- tcx.sess.target.int_type).unwrap();
values.push(discr);
*(targets.place_back() <- self.cfg.start_new_block())
} else {
}
debug!("num_enum_variants: {}, tested variants: {:?}, variants: {:?}",
num_enum_variants, values, variants);
- let discr_ty = adt_def.discr_ty.to_ty(tcx);
+ let discr_ty = adt_def.repr.discr_type().to_ty(tcx);
let discr = self.temp(discr_ty);
self.cfg.push_assign(block, source_info, &discr,
Rvalue::Discriminant(lvalue.clone()));
builder.finish(vec![], ty)
}
+pub fn construct_error<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
+ body_id: hir::BodyId)
+ -> Mir<'tcx> {
+ let span = hir.tcx().hir.span(hir.tcx().hir.body_owner(body_id));
+ let ty = hir.tcx().types.err;
+ let mut builder = Builder::new(hir, span, 0, ty);
+ let source_info = builder.source_info(span);
+ builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable);
+ builder.finish(vec![], ty)
+}
+
impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
fn new(hir: Cx<'a, 'gcx, 'tcx>,
span: Span,
/// resolving `break` and `continue`.
pub fn find_loop_scope(&mut self,
span: Span,
- label: Option<CodeExtent>)
+ label: CodeExtent)
-> &mut LoopScope<'tcx> {
- let loop_scopes = &mut self.loop_scopes;
- match label {
- None => {
- // no label? return the innermost loop scope
- loop_scopes.iter_mut().rev().next()
- }
- Some(label) => {
- // otherwise, find the loop-scope with the correct id
- loop_scopes.iter_mut()
- .rev()
- .filter(|loop_scope| loop_scope.extent == label)
- .next()
- }
- }.unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
+ // find the loop-scope with the correct id
+ self.loop_scopes.iter_mut()
+ .rev()
+ .filter(|loop_scope| loop_scope.extent == label)
+ .next()
+ .unwrap_or_else(|| span_bug!(span, "no enclosing loop scope found?"))
}
/// Given a span and the current visibility scope, make a SourceInfo.
use rustc::hir::map;
use rustc::hir::def::{Def, CtorKind};
use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
+use rustc_const_eval::{ConstContext, fatal_const_eval_err};
use rustc::ty::{self, AdtKind, VariantDef, Ty};
use rustc::ty::cast::CastKind as TyCastKind;
use rustc::hir;
kind: ExprKind::UnsafeFnPointer { source: expr.to_ref() },
};
}
+ Some((ty::adjustment::Adjust::ClosureFnPointer, adjusted_ty)) => {
+ expr = Expr {
+ temp_lifetime: temp_lifetime,
+ temp_lifetime_was_shrunk: was_shrunk,
+ ty: adjusted_ty,
+ span: self.span,
+ kind: ExprKind::ClosureFnPointer { source: expr.to_ref() },
+ };
+ }
Some((ty::adjustment::Adjust::NeverToAny, adjusted_ty)) => {
expr = Expr {
temp_lifetime: temp_lifetime,
let method = method_callee(cx, expr, ty::MethodCall::expr(expr.id));
- let sig = match method.ty.sty {
- ty::TyFnDef(.., fn_ty) => &fn_ty.sig,
- _ => span_bug!(expr.span, "type of method is not an fn"),
- };
+ let sig = method.ty.fn_sig();
let sig = cx.tcx
- .no_late_bound_regions(sig)
+ .no_late_bound_regions(&sig)
.unwrap_or_else(|| span_bug!(expr.span, "method call has late-bound regions"));
assert_eq!(sig.inputs().len(), 2);
hir::ExprRepeat(ref v, count) => {
let tcx = cx.tcx.global_tcx();
let c = &cx.tcx.hir.body(count).value;
- let count = match ConstContext::new(tcx, count).eval(c, EvalHint::ExprTypeChecked) {
+ let count = match ConstContext::new(tcx, count).eval(c) {
Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
Err(s) => fatal_const_eval_err(tcx, &s, c.span, "expression")
}
hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
hir::ExprBreak(label, ref value) => {
- ExprKind::Break {
- label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
- value: value.to_ref(),
+ match label.loop_id.into() {
+ Ok(loop_id) => ExprKind::Break {
+ label: cx.tcx.region_maps.node_extent(loop_id),
+ value: value.to_ref(),
+ },
+ Err(err) => bug!("invalid loop id for break: {}", err)
}
+
}
hir::ExprAgain(label) => {
- ExprKind::Continue {
- label: label.map(|label| cx.tcx.region_maps.node_extent(label.loop_id)),
+ match label.loop_id.into() {
+ Ok(loop_id) => ExprKind::Continue {
+ label: cx.tcx.region_maps.node_extent(loop_id),
+ },
+ Err(err) => bug!("invalid loop id for continue: {}", err)
}
}
hir::ExprMatch(ref discr, ref arms, _) => {
use rustc::mir::transform::MirSource;
use rustc::middle::const_val::ConstVal;
-use rustc_const_eval::{ConstContext, EvalHint, fatal_const_eval_err};
+use rustc_const_eval::{ConstContext, fatal_const_eval_err};
use rustc_data_structures::indexed_vec::Idx;
use rustc::hir::def_id::DefId;
use rustc::hir::map::blocks::FnLikeNode;
let mut check_overflow = attrs.iter()
.any(|item| item.check_name("rustc_inherit_overflow_checks"));
- // Respect -Z force-overflow-checks=on and -C debug-assertions.
- check_overflow |= infcx.tcx
- .sess
- .opts
- .debugging_opts
- .force_overflow_checks
- .unwrap_or(infcx.tcx.sess.opts.debug_assertions);
+ // Respect -C overflow-checks.
+ check_overflow |= infcx.tcx.sess.overflow_checks();
// Constants and const fn's always need overflow checks.
check_overflow |= constness == hir::Constness::Const;
pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
let tcx = self.tcx.global_tcx();
- match ConstContext::with_tables(tcx, self.tables()).eval(e, EvalHint::ExprTypeChecked) {
+ match ConstContext::with_tables(tcx, self.tables()).eval(e) {
Ok(value) => Literal::Value { value: value },
Err(s) => fatal_const_eval_err(tcx, &s, e.span, "expression")
}
ReifyFnPointer {
source: ExprRef<'tcx>,
},
+ ClosureFnPointer {
+ source: ExprRef<'tcx>,
+ },
UnsafeFnPointer {
source: ExprRef<'tcx>,
},
arg: ExprRef<'tcx>,
},
Break {
- label: Option<CodeExtent>,
+ label: CodeExtent,
value: Option<ExprRef<'tcx>>,
},
Continue {
- label: Option<CodeExtent>,
+ label: CodeExtent,
},
Return {
value: Option<ExprRef<'tcx>>,
pub mod pretty;
pub mod transform;
+use rustc::ty::maps::Providers;
+
+pub fn provide(providers: &mut Providers) {
+ mir_map::provide(providers);
+ transform::qualify_consts::provide(providers);
+}
//! - `#[rustc_mir(pretty="file.mir")]`
use build;
+use rustc::hir::def_id::DefId;
use rustc::dep_graph::DepNode;
use rustc::mir::Mir;
use rustc::mir::transform::MirSource;
use pretty;
use hair::cx::Cx;
-use rustc::infer::InferCtxt;
use rustc::traits::Reveal;
use rustc::ty::{self, Ty, TyCtxt};
+use rustc::ty::maps::Providers;
use rustc::ty::subst::Substs;
use rustc::hir;
use rustc::hir::intravisit::{Visitor, NestedVisitorMap};
use syntax::ast;
use syntax_pos::Span;
+use std::cell::RefCell;
use std::mem;
pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
}.as_deep_visitor());
}
+pub fn provide(providers: &mut Providers) {
+ providers.mir = build_mir;
+}
+
+fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+ -> &'tcx RefCell<Mir<'tcx>> {
+ let id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let unsupported = || {
+ span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
+ };
+
+ // Figure out what primary body this item has.
+ let body_id = match tcx.hir.get(id) {
+ hir::map::NodeItem(item) => {
+ match item.node {
+ hir::ItemConst(_, body) |
+ hir::ItemStatic(_, _, body) |
+ hir::ItemFn(.., body) => body,
+ _ => unsupported()
+ }
+ }
+ hir::map::NodeTraitItem(item) => {
+ match item.node {
+ hir::TraitItemKind::Const(_, Some(body)) |
+ hir::TraitItemKind::Method(_,
+ hir::TraitMethod::Provided(body)) => body,
+ _ => unsupported()
+ }
+ }
+ hir::map::NodeImplItem(item) => {
+ match item.node {
+ hir::ImplItemKind::Const(_, body) |
+ hir::ImplItemKind::Method(_, body) => body,
+ _ => unsupported()
+ }
+ }
+ hir::map::NodeExpr(expr) => {
+ // FIXME(eddyb) Closures should have separate
+ // function definition IDs and expression IDs.
+ // Type-checking should not let closures get
+ // this far in a constant position.
+ // Assume that everything other than closures
+ // is a constant "initializer" expression.
+ match expr.node {
+ hir::ExprClosure(_, _, body, _) => body,
+ _ => hir::BodyId { node_id: expr.id }
+ }
+ }
+ _ => unsupported()
+ };
+
+ let src = MirSource::from_node(tcx, id);
+ tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
+ let cx = Cx::new(&infcx, src);
+ let mut mir = if cx.tables().tainted_by_errors {
+ build::construct_error(cx, body_id)
+ } else if let MirSource::Fn(id) = src {
+ // fetch the fully liberated fn signature (that is, all bound
+ // types/lifetimes replaced)
+ let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
+
+ let ty = tcx.item_type(tcx.hir.local_def_id(id));
+ let mut abi = fn_sig.abi;
+ let implicit_argument = if let ty::TyClosure(..) = ty.sty {
+ // HACK(eddyb) Avoid having RustCall on closures,
+ // as it adds unnecessary (and wrong) auto-tupling.
+ abi = Abi::Rust;
+ Some((closure_self_ty(tcx, id, body_id), None))
+ } else {
+ None
+ };
+
+ let body = tcx.hir.body(body_id);
+ let explicit_arguments =
+ body.arguments
+ .iter()
+ .enumerate()
+ .map(|(index, arg)| {
+ (fn_sig.inputs()[index], Some(&*arg.pat))
+ });
+
+ let arguments = implicit_argument.into_iter().chain(explicit_arguments);
+ build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
+ } else {
+ build::construct_const(cx, body_id)
+ };
+
+ // Convert the Mir to global types.
+ let mut globalizer = GlobalizeMir {
+ tcx: tcx,
+ span: mir.span
+ };
+ globalizer.visit_mir(&mut mir);
+ let mir = unsafe {
+ mem::transmute::<Mir, Mir<'tcx>>(mir)
+ };
+
+ pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
+
+ tcx.alloc_mir(mir)
+ })
+}
+
/// A pass to lift all the types and substitutions in a Mir
/// to the global tcx. Sadly, we don't have a "folder" that
/// can change 'tcx so we have to transmute afterwards.
tcx: TyCtxt<'a, 'tcx, 'tcx>
}
-fn build<'a, 'gcx, 'tcx>(infcx: &InferCtxt<'a, 'gcx, 'tcx>,
- body_id: hir::BodyId)
- -> (Mir<'tcx>, MirSource) {
- let tcx = infcx.tcx.global_tcx();
-
- let item_id = tcx.hir.body_owner(body_id);
- let src = MirSource::from_node(tcx, item_id);
- let cx = Cx::new(infcx, src);
- if let MirSource::Fn(id) = src {
- // fetch the fully liberated fn signature (that is, all bound
- // types/lifetimes replaced)
- let fn_sig = cx.tables().liberated_fn_sigs[&id].clone();
-
- let ty = tcx.item_type(tcx.hir.local_def_id(id));
- let (abi, implicit_argument) = if let ty::TyClosure(..) = ty.sty {
- (Abi::Rust, Some((closure_self_ty(tcx, id, body_id), None)))
- } else {
- (ty.fn_abi(), None)
- };
-
- let body = tcx.hir.body(body_id);
- let explicit_arguments =
- body.arguments
- .iter()
- .enumerate()
- .map(|(index, arg)| {
- (fn_sig.inputs()[index], Some(&*arg.pat))
- });
-
- let arguments = implicit_argument.into_iter().chain(explicit_arguments);
- (build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body), src)
- } else {
- (build::construct_const(cx, body_id), src)
- }
-}
-
impl<'a, 'tcx> Visitor<'tcx> for BuildMir<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
NestedVisitorMap::None
}
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
- self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
- let (mut mir, src) = build(&infcx, body_id);
-
- // Convert the Mir to global types.
- let tcx = infcx.tcx.global_tcx();
- let mut globalizer = GlobalizeMir {
- tcx: tcx,
- span: mir.span
- };
- globalizer.visit_mir(&mut mir);
- let mir = unsafe {
- mem::transmute::<Mir, Mir<'tcx>>(mir)
- };
-
- pretty::dump_mir(tcx, "mir_map", &0, src, &mir);
-
- let mir = tcx.alloc_mir(mir);
- let def_id = tcx.hir.local_def_id(src.item_id());
- tcx.mir_map.borrow_mut().insert(def_id, mir);
- });
+ self.tcx.item_mir(self.tcx.hir.body_owner_def_id(body_id));
let body = self.tcx.hir.body(body_id);
self.visit_body(body);
use rustc_data_structures::bitvec::BitVector;
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
use rustc::hir::map::blocks::FnLikeNode;
use rustc::traits::{self, Reveal};
-use rustc::ty::{self, TyCtxt, Ty};
+use rustc::ty::{self, TyCtxt, Ty, TypeFoldable};
use rustc::ty::cast::CastTy;
+use rustc::ty::maps::Providers;
use rustc::mir::*;
use rustc::mir::traversal::ReversePostorder;
-use rustc::mir::transform::{Pass, MirPass, MirSource};
+use rustc::mir::transform::{Pass, MirMapPass, MirPassHook, MirSource};
use rustc::mir::visit::{LvalueContext, Visitor};
-use rustc::util::nodemap::DefIdMap;
use rustc::middle::lang_items;
use syntax::abi::Abi;
use syntax::feature_gate::UnstableFeatures;
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
-use std::collections::hash_map::Entry;
use std::fmt;
use std::usize;
bitflags! {
flags Qualif: u8 {
- // Const item's qualification while recursing.
- // Recursive consts are an error.
- const RECURSIVE = 1 << 0,
-
// Constant containing interior mutability (UnsafeCell).
- const MUTABLE_INTERIOR = 1 << 1,
+ const MUTABLE_INTERIOR = 1 << 0,
// Constant containing an ADT that implements Drop.
- const NEEDS_DROP = 1 << 2,
+ const NEEDS_DROP = 1 << 1,
// Function argument.
- const FN_ARGUMENT = 1 << 3,
+ const FN_ARGUMENT = 1 << 2,
// Static lvalue or move from a static.
- const STATIC = 1 << 4,
+ const STATIC = 1 << 3,
// Reference to a static.
- const STATIC_REF = 1 << 5,
+ const STATIC_REF = 1 << 4,
// Not constant at all - non-`const fn` calls, asm!,
// pointer comparisons, ptr-to-int casts, etc.
- const NOT_CONST = 1 << 6,
+ const NOT_CONST = 1 << 5,
// Refers to temporaries which cannot be promoted as
// promote_consts decided they weren't simple enough.
- const NOT_PROMOTABLE = 1 << 7,
+ const NOT_PROMOTABLE = 1 << 6,
// Borrows of temporaries can be promoted only
// if they have none of the above qualifications.
- const NEVER_PROMOTE = !0,
+ const NEVER_PROMOTE = 0b111_1111,
// Const items can only have MUTABLE_INTERIOR
// and NOT_PROMOTABLE without producing an error.
rpo: ReversePostorder<'a, 'tcx>,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
param_env: ty::ParameterEnvironment<'tcx>,
- qualif_map: &'a mut DefIdMap<Qualif>,
temp_qualif: IndexVec<Local, Option<Qualif>>,
return_qualif: Option<Qualif>,
qualif: Qualif,
impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParameterEnvironment<'tcx>,
- qualif_map: &'a mut DefIdMap<Qualif>,
def_id: DefId,
mir: &'a Mir<'tcx>,
mode: Mode)
rpo: rpo,
tcx: tcx,
param_env: param_env,
- qualif_map: qualif_map,
temp_qualif: IndexVec::from_elem(None, &mir.local_decls),
return_qualif: None,
qualif: Qualif::empty(),
if substs.types().next().is_some() {
self.add_type(constant.ty);
} else {
- let qualif = qualify_const_item_cached(self.tcx,
- self.qualif_map,
- def_id);
- self.add(qualif);
- }
+ let bits = ty::queries::mir_const_qualif::get(self.tcx,
+ constant.span,
+ def_id);
- // FIXME(eddyb) check recursive constants here,
- // instead of rustc_passes::static_recursion.
- if self.qualif.intersects(Qualif::RECURSIVE) {
- span_bug!(constant.span,
- "recursive constant wasn't caught earlier");
+ let qualif = Qualif::from_bits(bits).expect("invalid mir_const_qualif");
+ self.add(qualif);
}
// Let `const fn` transitively have destructors,
Rvalue::CheckedBinaryOp(..) |
Rvalue::Cast(CastKind::ReifyFnPointer, ..) |
Rvalue::Cast(CastKind::UnsafeFnPointer, ..) |
+ Rvalue::Cast(CastKind::ClosureFnPointer, ..) |
Rvalue::Cast(CastKind::Unsize, ..) => {}
Rvalue::Len(_) => {
Rvalue::Aggregate(ref kind, _) => {
if let AggregateKind::Adt(def, ..) = *kind {
- if def.has_dtor() {
+ if def.has_dtor(self.tcx) {
self.add(Qualif::NEEDS_DROP);
self.deny_drop();
}
let fn_ty = func.ty(self.mir, self.tcx);
let (is_shuffle, is_const_fn) = match fn_ty.sty {
ty::TyFnDef(def_id, _, f) => {
- (f.abi == Abi::PlatformIntrinsic &&
+ (f.abi() == Abi::PlatformIntrinsic &&
self.tcx.item_name(def_id).as_str().starts_with("simd_shuffle"),
is_const_fn(self.tcx, def_id))
}
}
}
-fn qualify_const_item_cached<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- qualif_map: &mut DefIdMap<Qualif>,
- def_id: DefId)
- -> Qualif {
- match qualif_map.entry(def_id) {
- Entry::Occupied(entry) => return *entry.get(),
- Entry::Vacant(entry) => {
- // Guard against `const` recursion.
- entry.insert(Qualif::RECURSIVE);
- }
+pub fn provide(providers: &mut Providers) {
+ providers.mir_const_qualif = qualify_const_item;
+}
+
+fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> u8 {
+ let mir = &tcx.item_mir(def_id);
+ if mir.return_ty.references_error() {
+ return Qualif::NOT_CONST.bits();
}
- let param_env = if def_id.is_local() {
- let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
- ty::ParameterEnvironment::for_item(tcx, node_id)
- } else {
- // These should only be monomorphic constants.
- tcx.empty_parameter_environment()
- };
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let param_env = ty::ParameterEnvironment::for_item(tcx, node_id);
- let mir = &tcx.item_mir(def_id);
- let mut qualifier = Qualifier::new(tcx, param_env, qualif_map, def_id, mir, Mode::Const);
- let qualif = qualifier.qualify_const();
- qualifier.qualif_map.insert(def_id, qualif);
- qualif
+ let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, Mode::Const);
+ qualifier.qualify_const().bits()
}
-#[derive(Default)]
-pub struct QualifyAndPromoteConstants {
- qualif_map: DefIdMap<Qualif>
-}
+pub struct QualifyAndPromoteConstants;
impl Pass for QualifyAndPromoteConstants {}
-impl<'tcx> MirPass<'tcx> for QualifyAndPromoteConstants {
+impl<'tcx> MirMapPass<'tcx> for QualifyAndPromoteConstants {
+ fn run_pass<'a>(&mut self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ hooks: &mut [Box<for<'s> MirPassHook<'s>>])
+ {
+ let def_ids = tcx.maps.mir.borrow().keys();
+ for def_id in def_ids {
+ if !def_id.is_local() {
+ continue;
+ }
+
+ let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
+ let id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let src = MirSource::from_node(tcx, id);
+
+ if let MirSource::Const(_) = src {
+ ty::queries::mir_const_qualif::get(tcx, DUMMY_SP, def_id);
+ continue;
+ }
+
+ let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
+ tcx.dep_graph.write(DepNode::Mir(def_id));
+
+ for hook in &mut *hooks {
+ hook.on_mir_pass(tcx, src, mir, self, false);
+ }
+ self.run_pass(tcx, src, mir);
+ for hook in &mut *hooks {
+ hook.on_mir_pass(tcx, src, mir, self, true);
+ }
+ }
+ }
+}
+
+impl<'tcx> QualifyAndPromoteConstants {
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
src: MirSource, mir: &mut Mir<'tcx>) {
let id = src.item_id();
Mode::Fn
}
}
- MirSource::Const(_) => {
- match self.qualif_map.entry(def_id) {
- Entry::Occupied(_) => return,
- Entry::Vacant(entry) => {
- // Guard against `const` recursion.
- entry.insert(Qualif::RECURSIVE);
- Mode::Const
- }
- }
- }
MirSource::Static(_, hir::MutImmutable) => Mode::Static,
MirSource::Static(_, hir::MutMutable) => Mode::StaticMut,
+ MirSource::Const(_) |
MirSource::Promoted(..) => return
};
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
// which can't be mutated until its scope ends.
let (temps, candidates) = {
let mut qualifier = Qualifier::new(tcx, param_env,
- &mut self.qualif_map,
def_id, mir, mode);
if mode == Mode::ConstFn {
// Enforce a constant-like CFG for `const fn`.
// Do the actual promotion, now that we know what's viable.
promote_consts::promote_candidates(mir, tcx, temps, candidates);
} else {
- let mut qualifier = Qualifier::new(tcx, param_env,
- &mut self.qualif_map,
- def_id, mir, mode);
- let qualif = qualifier.qualify_const();
-
- if mode == Mode::Const {
- qualifier.qualif_map.insert(def_id, qualif);
- }
+ let mut qualifier = Qualifier::new(tcx, param_env, def_id, mir, mode);
+ qualifier.qualify_const();
}
// Statics must be Sync.
if mode == Mode::Static {
let ty = mir.return_ty;
- tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
let cause = traits::ObligationCause::new(mir.span, id, traits::SharedStatic);
let mut fulfillment_cx = traits::FulfillmentContext::new();
fulfillment_cx.register_bound(&infcx, ty,
TerminatorKind::Call { ref func, ref args, ref destination, .. } => {
let func_ty = func.ty(mir, tcx);
debug!("check_terminator: call, func_ty={:?}", func_ty);
- let func_ty = match func_ty.sty {
- ty::TyFnDef(.., func_ty) | ty::TyFnPtr(func_ty) => func_ty,
+ let sig = match func_ty.sty {
+ ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => sig,
_ => {
span_mirbug!(self, term, "call to non-function {:?}", func_ty);
return;
}
};
- let sig = tcx.erase_late_bound_regions(&func_ty.sig);
+ let sig = tcx.erase_late_bound_regions(&sig);
let sig = self.normalize(&sig);
self.check_call_dest(mir, term, &sig, destination);
return;
}
let param_env = ty::ParameterEnvironment::for_item(tcx, src.item_id());
- tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
let mut checker = TypeChecker::new(&infcx, src.item_id());
{
let mut verifier = TypeVerifier::new(&mut checker, mir);
use rustc::ty::cast::CastKind;
use rustc_const_eval::{ConstEvalErr, ConstContext};
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
-use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath, BadType};
-use rustc_const_eval::ErrKind::UnresolvedPath;
-use rustc_const_eval::EvalHint::ExprTypeChecked;
+use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
+use rustc_const_eval::ErrKind::{TypeckError};
use rustc_const_math::{ConstMathErr, Op};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
fn check_const_eval(&self, expr: &'gcx hir::Expr) {
let const_cx = ConstContext::with_tables(self.tcx, self.tables);
- if let Err(err) = const_cx.eval(expr, ExprTypeChecked) {
+ if let Err(err) = const_cx.eval(expr) {
match err.kind {
UnimplementedConstVal(_) => {}
IndexOpFeatureGated => {}
ErroneousReferencedConstant(_) => {}
- BadType(_) => {}
+ TypeckError => {}
_ => {
self.tcx.sess.add_lint(CONST_ERR,
expr.id,
self.check_const_eval(&body.value);
}
- let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
+ let outer_penv = self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
let param_env = infcx.parameter_environment.clone();
let outer_penv = mem::replace(&mut self.param_env, param_env);
euv::ExprUseVisitor::new(self, &infcx).consume_body(body);
if self.in_fn && self.promotable {
let const_cx = ConstContext::with_tables(self.tcx, self.tables);
- match const_cx.eval(ex, ExprTypeChecked) {
+ match const_cx.eval(ex) {
Ok(_) => {}
Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
Err(ConstEvalErr { kind: MiscCatchAll, .. }) |
Err(ConstEvalErr { kind: MiscBinaryOp, .. }) |
Err(ConstEvalErr { kind: NonConstPath, .. }) |
- Err(ConstEvalErr { kind: UnresolvedPath, .. }) |
Err(ConstEvalErr { kind: ErroneousReferencedConstant(_), .. }) |
Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shr)), .. }) |
Err(ConstEvalErr { kind: Math(ConstMathErr::Overflow(Op::Shl)), .. }) |
Err(ConstEvalErr { kind: IndexOpFeatureGated, .. }) => {}
- Err(ConstEvalErr { kind: BadType(_), .. }) => {}
+ Err(ConstEvalErr { kind: TypeckError, .. }) => {}
Err(msg) => {
self.tcx.sess.add_lint(CONST_ERR,
ex.id,
/// instead of producing errors.
fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>, e: &hir::Expr, node_ty: Ty<'tcx>) {
match node_ty.sty {
- ty::TyAdt(def, _) if def.has_dtor() => {
+ ty::TyAdt(def, _) if def.has_dtor(v.tcx) => {
v.promotable = false;
}
_ => {}
Some(Adjust::NeverToAny) |
Some(Adjust::ReifyFnPointer) |
Some(Adjust::UnsafeFnPointer) |
+ Some(Adjust::ClosureFnPointer) |
Some(Adjust::MutToConstPointer) => {}
Some(Adjust::DerefRef { autoderefs, .. }) => {
}
```
"##,
+
+E0590: r##"
+`break` or `continue` must include a label when used in the condition of a
+`while` loop.
+
+Example of erroneous code:
+
+```compile_fail
+while break {}
+```
+
+To fix this, add a label specifying which loop is being broken out of:
+```
+`foo: while break `foo {}
+```
+"##
}
register_diagnostics! {
self.with_context(Closure, |v| v.visit_nested_body(b));
}
hir::ExprBreak(label, ref opt_expr) => {
+ let loop_id = match label.loop_id.into() {
+ Ok(loop_id) => loop_id,
+ Err(hir::LoopIdError::OutsideLoopScope) => ast::DUMMY_NODE_ID,
+ Err(hir::LoopIdError::UnlabeledCfInWhileCondition) => {
+ self.emit_unlabled_cf_in_while_condition(e.span, "break");
+ ast::DUMMY_NODE_ID
+ },
+ Err(hir::LoopIdError::UnresolvedLabel) => ast::DUMMY_NODE_ID,
+ };
+
if opt_expr.is_some() {
- let loop_kind = if let Some(label) = label {
- if label.loop_id == ast::DUMMY_NODE_ID {
- None
- } else {
- Some(match self.hir_map.expect_expr(label.loop_id).node {
- hir::ExprWhile(..) => LoopKind::WhileLoop,
- hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
- ref r => span_bug!(e.span,
- "break label resolved to a non-loop: {:?}", r),
- })
- }
- } else if let Loop(kind) = self.cx {
- Some(kind)
- } else {
- // `break` outside a loop - caught below
+ let loop_kind = if loop_id == ast::DUMMY_NODE_ID {
None
+ } else {
+ Some(match self.hir_map.expect_expr(loop_id).node {
+ hir::ExprWhile(..) => LoopKind::WhileLoop,
+ hir::ExprLoop(_, _, source) => LoopKind::Loop(source),
+ ref r => span_bug!(e.span,
+ "break label resolved to a non-loop: {:?}", r),
+ })
};
match loop_kind {
None | Some(LoopKind::Loop(hir::LoopSource::Loop)) => (),
}
}
}
+
self.require_loop("break", e.span);
}
- hir::ExprAgain(_) => self.require_loop("continue", e.span),
+ hir::ExprAgain(label) => {
+ if let Err(hir::LoopIdError::UnlabeledCfInWhileCondition) = label.loop_id.into() {
+ self.emit_unlabled_cf_in_while_condition(e.span, "continue");
+ }
+ self.require_loop("continue", e.span)
+ },
_ => intravisit::walk_expr(self, e),
}
}
}
}
}
+
+ fn emit_unlabled_cf_in_while_condition(&mut self, span: Span, cf_type: &str) {
+ struct_span_err!(self.sess, span, E0590,
+ "`break` or `continue` with no label in the condition of a `while` loop")
+ .span_label(span,
+ &format!("unlabeled `{}` in the condition of a `while` loop", cf_type))
+ .emit();
+ }
}
// For debugging instrumentation like this, we don't need to worry
// about maintaining the dep graph.
let _ignore = tcx.dep_graph.in_ignore();
- let mir_map = tcx.mir_map.borrow();
+ let mir_map = tcx.maps.mir.borrow();
for def_id in mir_map.keys() {
let mir = mir_map.get(&def_id).unwrap();
collector.visit_mir(&mir.borrow());
fn visit_nested_body(&mut self, body_id: hir::BodyId) {
let body = self.tcx.hir.body(body_id);
- self.tcx.infer_ctxt(body_id, Reveal::NotSpecializable).enter(|infcx| {
+ self.tcx.infer_ctxt(body_id, Reveal::UserFacing).enter(|infcx| {
let mut delegate = RvalueContextDelegate {
tcx: infcx.tcx,
param_env: &infcx.parameter_environment
use rustc::util::nodemap::{NodeMap, NodeSet};
use syntax::ast;
-use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax_pos::Span;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir;
match it.node {
hir::ItemStatic(..) |
hir::ItemConst(..) => {
- let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &it.span);
+ let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
recursion_visitor.visit_item(it);
}
hir::ItemEnum(ref enum_def, ref generics) => {
// less redundant output.
for variant in &enum_def.variants {
if let Some(_) = variant.node.disr_expr {
- let mut recursion_visitor = CheckItemRecursionVisitor::new(self,
- &variant.span);
+ let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
recursion_visitor.populate_enum_discriminants(enum_def);
recursion_visitor.visit_variant(variant, generics, it.id);
}
match ti.node {
hir::TraitItemKind::Const(_, ref default) => {
if let Some(_) = *default {
- let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ti.span);
+ let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
recursion_visitor.visit_trait_item(ti);
}
}
fn visit_impl_item(&mut self, ii: &'hir hir::ImplItem) {
match ii.node {
hir::ImplItemKind::Const(..) => {
- let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ii.span);
+ let mut recursion_visitor = CheckItemRecursionVisitor::new(self);
recursion_visitor.visit_impl_item(ii);
}
_ => {}
}
struct CheckItemRecursionVisitor<'a, 'b: 'a, 'hir: 'b> {
- root_span: &'b Span,
sess: &'b Session,
hir_map: &'b hir_map::Map<'hir>,
discriminant_map: &'a mut NodeMap<Option<hir::BodyId>>,
}
impl<'a, 'b: 'a, 'hir: 'b> CheckItemRecursionVisitor<'a, 'b, 'hir> {
- fn new(v: &'a mut CheckCrateVisitor<'b, 'hir>, span: &'b Span) -> Self {
+ fn new(v: &'a mut CheckCrateVisitor<'b, 'hir>) -> Self {
CheckItemRecursionVisitor {
- root_span: span,
sess: v.sess,
hir_map: v.hir_map,
discriminant_map: &mut v.discriminant_map,
false
}
});
- if any_static {
- if !self.sess.features.borrow().static_recursion {
- emit_feature_err(&self.sess.parse_sess,
- "static_recursion",
- *self.root_span,
- GateIssue::Language,
- "recursive static");
- }
- } else {
+ if !any_static {
struct_span_err!(self.sess, span, E0265, "recursive constant")
.span_label(span, &format!("recursion not allowed in constant"))
.emit();
impl<'b, 'a, 'tcx> ReachEverythingInTheInterfaceVisitor<'b, 'a, 'tcx> {
fn generics(&mut self) -> &mut Self {
- self.ev.tcx.item_generics(self.item_def_id).visit_with(self);
+ for def in &self.ev.tcx.item_generics(self.item_def_id).types {
+ if def.has_default {
+ self.ev.tcx.item_type(def.def_id).visit_with(self);
+ }
+ }
self
}
impl<'a, 'tcx: 'a> SearchInterfaceForPrivateItemsVisitor<'a, 'tcx> {
fn generics(&mut self) -> &mut Self {
- self.tcx.item_generics(self.item_def_id).visit_with(self);
+ for def in &self.tcx.item_generics(self.item_def_id).types {
+ if def.has_default {
+ self.tcx.item_type(def.def_id).visit_with(self);
+ }
+ }
self
}
self.define(module, ident, ns, (child.def, ty::Visibility::Public,
DUMMY_SP, Mark::root()));
- let has_self = self.session.cstore.associated_item(child.def.def_id())
- .map_or(false, |item| item.method_has_self_argument);
+ let has_self = self.session.cstore.associated_item_cloned(child.def.def_id())
+ .method_has_self_argument;
self.trait_item_map.insert((def_id, child.name, ns), (child.def, has_self));
}
module.populated.set(true);
pub fn get_macro(&mut self, def: Def) -> Rc<SyntaxExtension> {
let def_id = match def {
- Def::Macro(def_id) => def_id,
+ Def::Macro(def_id, ..) => def_id,
_ => panic!("Expected Def::Macro(..)"),
};
if let Some(ext) = self.macro_map.get(&def_id) {
binding: &'a NameBinding<'a>,
span: Span,
allow_shadowing: bool) {
- self.macro_names.insert(name);
if self.builtin_macros.insert(name, binding).is_some() && !allow_shadowing {
let msg = format!("`{}` is already in scope", name);
let note =
// use `gq` to wrap paragraphs. Use `:set tw=0` to disable.
register_long_diagnostics! {
+E0128: r##"
+Type parameter defaults can only use parameters that occur before them.
+Erroneous code example:
+
+```compile_fail,E0128
+struct Foo<T=U, U=()> {
+ field1: T,
+ filed2: U,
+}
+// error: type parameters with a default cannot use forward declared
+// identifiers
+```
+
+Since type parameters are evaluated in-order, you may be able to fix this issue
+by doing:
+
+```
+struct Foo<U=(), T=U> {
+ field1: T,
+ filed2: U,
+}
+```
+
+Please also verify that this wasn't because of a name-clash and rename the type
+parameter if so.
+"##,
+
E0154: r##"
## Note: this error code is no longer emitted by the compiler.
AttemptToUseNonConstantValueInConstant,
/// error E0530: X bindings cannot shadow Ys
BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>),
+ /// error E0128: type parameters with a default cannot use forward declared identifiers
+ ForwardDeclaredTyParam,
}
fn resolve_error<'sess, 'a>(resolver: &'sess Resolver,
err.span_label(binding.span, msg);
err
}
+ ResolutionError::ForwardDeclaredTyParam => {
+ let mut err = struct_span_err!(resolver.session, span, E0128,
+ "type parameters with a default cannot use \
+ forward declared identifiers");
+ err.span_label(span, &format!("defaulted type parameters \
+ cannot be forward declared"));
+ err
+ }
}
}
self.label_ribs.pop();
self.ribs[ValueNS].pop();
}
+ fn visit_generics(&mut self, generics: &'tcx Generics) {
+ // For type parameter defaults, we have to ban access
+ // to following type parameters, as the Substs can only
+ // provide previous type parameters as they're built.
+ let mut default_ban_rib = Rib::new(ForwardTyParamBanRibKind);
+ default_ban_rib.bindings.extend(generics.ty_params.iter()
+ .skip_while(|p| p.default.is_none())
+ .map(|p| (Ident::with_empty_ctxt(p.ident.name), Def::Err)));
+
+ for param in &generics.ty_params {
+ for bound in ¶m.bounds {
+ self.visit_ty_param_bound(bound);
+ }
+
+ if let Some(ref ty) = param.default {
+ self.ribs[TypeNS].push(default_ban_rib);
+ self.visit_ty(ty);
+ default_ban_rib = self.ribs[TypeNS].pop().unwrap();
+ }
+
+ // Allow all following defaults to refer to this type parameter.
+ default_ban_rib.bindings.remove(&Ident::with_empty_ctxt(param.ident.name));
+ }
+ for lt in &generics.lifetimes { self.visit_lifetime_def(lt); }
+ for p in &generics.where_clause.predicates { self.visit_where_predicate(p); }
+ }
}
pub type ErrorMessage = Option<(Span, String)>;
// We passed through a `macro_rules!` statement with the given expansion
MacroDefinition(Mark),
+
+ // All bindings in this rib are type parameters that can't be used
+ // from the default of a type parameter because they're not declared
+ // before said type parameter. Also see the `visit_generics` override.
+ ForwardTyParamBanRibKind,
}
/// One local scope.
}
}
-/// A definition along with the index of the rib it was found on
-#[derive(Copy, Clone, Debug)]
-struct LocalDef {
- ribs: Option<(Namespace, usize)>,
- def: Def,
-}
-
enum LexicalScopeBinding<'a> {
Item(&'a NameBinding<'a>),
Def(Def),
ribs: PerNS {
value_ns: vec![Rib::new(ModuleRibKind(graph_root))],
type_ns: vec![Rib::new(ModuleRibKind(graph_root))],
- macro_ns: None,
+ macro_ns: Some(vec![Rib::new(ModuleRibKind(graph_root))]),
},
label_ribs: Vec::new(),
if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
// The ident resolves to a type parameter or local variable.
return Some(LexicalScopeBinding::Def(
- self.adjust_local_def(LocalDef { ribs: Some((ns, i)), def: def }, record_used)
+ self.adjust_local_def(ns, i, def, record_used)
));
}
};
}
}
- if primary_ns != MacroNS && path.len() == 1 &&
- self.macro_names.contains(&path[0].name) {
+ let is_builtin = self.builtin_macros.get(&path[0].name).cloned()
+ .map(|binding| binding.get_macro(self).kind() == MacroKind::Bang).unwrap_or(false);
+ if primary_ns != MacroNS && (is_builtin || self.macro_names.contains(&path[0].name)) {
// Return some dummy definition, it's enough for error reporting.
- return Some(PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX))));
+ return Some(
+ PathResolution::new(Def::Macro(DefId::local(CRATE_DEF_INDEX), MacroKind::Bang))
+ );
}
fin_res
}
}
// Resolve a local definition, potentially adjusting for closures.
- fn adjust_local_def(&mut self, local_def: LocalDef, record_used: Option<Span>) -> Def {
- let ribs = match local_def.ribs {
- Some((ns, i)) => &self.ribs[ns][i + 1..],
- None => &[] as &[_],
- };
- let mut def = local_def.def;
+ fn adjust_local_def(&mut self,
+ ns: Namespace,
+ rib_index: usize,
+ mut def: Def,
+ record_used: Option<Span>) -> Def {
+ let ribs = &self.ribs[ns][rib_index + 1..];
+
+ // An invalid forward use of a type parameter from a previous default.
+ if let ForwardTyParamBanRibKind = self.ribs[ns][rib_index].kind {
+ if let Some(span) = record_used {
+ resolve_error(self, span,
+ ResolutionError::ForwardDeclaredTyParam);
+ }
+ assert_eq!(def, Def::Err);
+ return Def::Err;
+ }
+
match def {
Def::Upvar(..) => {
span_bug!(record_used.unwrap_or(DUMMY_SP), "unexpected {:?} in bindings", def)
Def::Local(def_id) => {
for rib in ribs {
match rib.kind {
- NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) => {
+ NormalRibKind | ModuleRibKind(..) | MacroDefinition(..) |
+ ForwardTyParamBanRibKind => {
// Nothing to do. Continue.
}
ClosureRibKind(function_id) => {
for rib in ribs {
match rib.kind {
NormalRibKind | MethodRibKind(_) | ClosureRibKind(..) |
- ModuleRibKind(..) | MacroDefinition(..) => {
+ ModuleRibKind(..) | MacroDefinition(..) | ForwardTyParamBanRibKind => {
// Nothing to do. Continue.
}
ItemRibKind => {
}
}
- fn resolve_labeled_block(&mut self, label: Option<SpannedIdent>, id: NodeId, block: &Block) {
+ fn with_resolved_label<F>(&mut self, label: Option<SpannedIdent>, id: NodeId, f: F)
+ where F: FnOnce(&mut Resolver)
+ {
if let Some(label) = label {
let def = Def::Label(id);
self.with_label_rib(|this| {
this.label_ribs.last_mut().unwrap().bindings.insert(label.node, def);
- this.visit_block(block);
+ f(this);
});
} else {
- self.visit_block(block);
+ f(self);
}
}
+ fn resolve_labeled_block(&mut self, label: Option<SpannedIdent>, id: NodeId, block: &Block) {
+ self.with_resolved_label(label, id, |this| this.visit_block(block));
+ }
+
fn resolve_expr(&mut self, expr: &Expr, parent: Option<&ExprKind>) {
// First, record candidate traits for this expression if it could
// result in the invocation of a method call.
ExprKind::Loop(ref block, label) => self.resolve_labeled_block(label, expr.id, &block),
ExprKind::While(ref subexpression, ref block, label) => {
- self.visit_expr(subexpression);
- self.resolve_labeled_block(label, expr.id, &block);
+ self.with_resolved_label(label, expr.id, |this| {
+ this.visit_expr(subexpression);
+ this.visit_block(block);
+ });
}
ExprKind::WhileLet(ref pattern, ref subexpression, ref block, label) => {
- self.visit_expr(subexpression);
- self.ribs[ValueNS].push(Rib::new(NormalRibKind));
- self.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
-
- self.resolve_labeled_block(label, expr.id, block);
-
- self.ribs[ValueNS].pop();
+ self.with_resolved_label(label, expr.id, |this| {
+ this.visit_expr(subexpression);
+ this.resolve_pattern(pattern, PatternSource::WhileLet, &mut FxHashMap());
+ this.visit_block(block);
+ });
}
ExprKind::ForLoop(ref pattern, ref subexpression, ref block, label) => {
use syntax::attr;
use syntax::errors::DiagnosticBuilder;
use syntax::ext::base::{self, Determinacy, MultiModifier, MultiDecorator};
-use syntax::ext::base::{NormalTT, Resolver as SyntaxResolver, SyntaxExtension};
+use syntax::ext::base::{Resolver as SyntaxResolver, SyntaxExtension};
use syntax::ext::base::MacroKind;
use syntax::ext::expand::{Expansion, mark_tts};
use syntax::ext::hygiene::Mark;
}
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>) {
- if let NormalTT(..) = *ext {
- self.macro_names.insert(ident.name);
- }
let def_id = DefId {
krate: BUILTIN_MACROS_CRATE,
index: DefIndex::new(self.macro_map.len()),
};
+ let kind = ext.kind();
self.macro_map.insert(def_id, ext);
let binding = self.arenas.alloc_name_binding(NameBinding {
- kind: NameBindingKind::Def(Def::Macro(def_id)),
+ kind: NameBindingKind::Def(Def::Macro(def_id, kind)),
span: DUMMY_SP,
vis: ty::Visibility::Invisible,
expansion: Mark::root(),
fn suggest_macro_name(&mut self, name: &str, kind: MacroKind,
err: &mut DiagnosticBuilder<'a>) {
- let suggestion = match kind {
- MacroKind::Bang =>
- find_best_match_for_name(self.macro_names.iter(), name, None),
- MacroKind::Attr |
- MacroKind::Derive => {
- // Find a suggestion from the legacy namespace.
- // FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
- let builtin_macros = self.builtin_macros.clone();
- let names = builtin_macros.iter().filter_map(|(name, binding)| {
- if binding.get_macro(self).kind() == kind {
- Some(name)
- } else {
- None
- }
- });
- find_best_match_for_name(names, name, None)
+ // First check if this is a locally-defined bang macro.
+ let suggestion = if let MacroKind::Bang = kind {
+ find_best_match_for_name(self.macro_names.iter(), name, None)
+ } else {
+ None
+ // Then check builtin macros.
+ }.or_else(|| {
+ // FIXME: get_macro needs an &mut Resolver, can we do it without cloning?
+ let builtin_macros = self.builtin_macros.clone();
+ let names = builtin_macros.iter().filter_map(|(name, binding)| {
+ if binding.get_macro(self).kind() == kind {
+ Some(name)
+ } else {
+ None
+ }
+ });
+ find_best_match_for_name(names, name, None)
+ // Then check modules.
+ }).or_else(|| {
+ if !self.use_extern_macros {
+ return None;
}
- };
+ let is_macro = |def| {
+ if let Def::Macro(_, def_kind) = def {
+ def_kind == kind
+ } else {
+ false
+ }
+ };
+ let ident = Ident::from_str(name);
+ self.lookup_typo_candidate(&vec![ident], MacroNS, is_macro)
+ .as_ref().map(|s| Symbol::intern(s))
+ });
+
if let Some(suggestion) = suggestion {
if suggestion != name {
if let MacroKind::Bang = kind {
});
self.macro_exports.push(Export {
name: def.ident.name,
- def: Def::Macro(self.definitions.local_def_id(def.id)),
+ def: Def::Macro(self.definitions.local_def_id(def.id), MacroKind::Bang),
});
self.exported_macros.push(def);
}
where F: FnOnce(&mut DumpVisitor<'l, 'tcx, 'll, D>)
{
let item_def_id = self.tcx.hir.local_def_id(item_id);
- match self.tcx.tables.borrow().get(&item_def_id) {
+ match self.tcx.maps.typeck_tables.borrow().get(&item_def_id) {
Some(tables) => {
let old_tables = self.save_ctxt.tables;
self.save_ctxt.tables = tables;
Def::AssociatedTy(..) |
Def::AssociatedConst(..) |
Def::PrimTy(_) |
- Def::Macro(_) |
+ Def::Macro(..) |
Def::Err => {
span_bug!(span,
"process_def_kind for unexpected item: {:?}",
pub struct SaveContext<'l, 'tcx: 'l> {
tcx: TyCtxt<'l, 'tcx, 'tcx>,
tables: &'l ty::TypeckTables<'tcx>,
- analysis: &'l ty::CrateAnalysis<'tcx>,
+ analysis: &'l ty::CrateAnalysis,
span_utils: SpanUtils<'tcx>,
}
match *qpath {
hir::QPath::Resolved(_, ref path) => path.def,
hir::QPath::TypeRelative(..) => {
- if let Some(ty) = self.analysis.hir_ty_to_ty.get(&id) {
+ if let Some(ty) = self.tcx.ast_ty_to_ty_cache.borrow().get(&id) {
if let ty::TyProjection(proj) = ty.sty {
for item in self.tcx.associated_items(proj.trait_ref.def_id) {
if item.kind == ty::AssociatedKind::Type {
pub fn process_crate<'l, 'tcx>(tcx: TyCtxt<'l, 'tcx, 'tcx>,
krate: &ast::Crate,
- analysis: &'l ty::CrateAnalysis<'tcx>,
+ analysis: &'l ty::CrateAnalysis,
cratename: &str,
odir: Option<&Path>,
format: Format) {
use std::path::Path;
use syntax::ast;
-use syntax::parse::filemap_to_tts;
use syntax::parse::lexer::{self, StringReader};
use syntax::parse::token::{self, Token};
use syntax::symbol::keywords;
}
}
- // sub_span starts at span.lo, so we need to adjust the positions etc.
- // If sub_span is None, we don't need to adjust.
- pub fn make_sub_span(&self, span: Span, sub_span: Option<Span>) -> Option<Span> {
- match sub_span {
- None => None,
- Some(sub) => {
- let FileMapAndBytePos {fm, pos} = self.sess.codemap().lookup_byte_offset(span.lo);
- let base = pos + fm.start_pos;
- Some(Span {
- lo: base + self.sess.codemap().lookup_byte_offset(sub.lo).pos,
- hi: base + self.sess.codemap().lookup_byte_offset(sub.hi).pos,
- expn_id: span.expn_id,
- })
- }
- }
- }
-
pub fn snippet(&self, span: Span) -> String {
match self.sess.codemap().span_to_snippet(span) {
Ok(s) => s,
}
pub fn retokenise_span(&self, span: Span) -> StringReader<'a> {
- // sadness - we don't have spans for sub-expressions nor access to the tokens
- // so in order to get extents for the function name itself (which dxr expects)
- // we need to re-tokenise the fn definition
-
- // Note: this is a bit awful - it adds the contents of span to the end of
- // the codemap as a new filemap. This is mostly OK, but means we should
- // not iterate over the codemap. Also, any spans over the new filemap
- // are incompatible with spans over other filemaps.
- let filemap = self.sess
- .codemap()
- .new_filemap(String::from("<anon-dxr>"), None, self.snippet(span));
- lexer::StringReader::new(&self.sess.parse_sess, filemap)
- }
-
- fn span_to_tts(&self, span: Span) -> Vec<TokenTree> {
- let filename = String::from("<anon-dxr>");
- let filemap = self.sess.codemap().new_filemap(filename, None, self.snippet(span));
- filemap_to_tts(&self.sess.parse_sess, filemap)
+ lexer::StringReader::retokenize(&self.sess.parse_sess, span)
}
// Re-parses a path and returns the span for the last identifier in the path
loop {
let ts = toks.real_token();
if ts.tok == token::Eof {
- return self.make_sub_span(span, result)
+ return result
}
if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
result = Some(ts.sp);
return None;
}
if bracket_count == 0 && (ts.tok.is_ident() || ts.tok.is_keyword(keywords::SelfValue)) {
- return self.make_sub_span(span, Some(ts.sp));
+ return Some(ts.sp);
}
bracket_count += match ts.tok {
}
prev = next;
}
- if result.is_none() && prev_span.is_some() {
- return self.make_sub_span(span, prev_span);
- }
- return self.make_sub_span(span, result);
+ result.or(prev_span)
}
// Return the span for the last ident before a `<` and outside any
loc.line);
}
if result.is_none() && prev.tok.is_ident() && angle_count == 0 {
- return self.make_sub_span(span, Some(prev.sp));
+ return Some(prev.sp);
}
- self.make_sub_span(span, result)
+ result
}
// Reparse span and return an owned vector of sub spans of the first limit
angle_count += 1;
}
if ts.tok.is_ident() && angle_count == nesting {
- result.push(self.make_sub_span(span, Some(ts.sp)).unwrap());
+ result.push(ts.sp);
}
}
}
/// end of the 'signature' part, that is up to, but not including an opening
/// brace or semicolon.
pub fn signature_string_for_span(&self, span: Span) -> String {
- let mut toks = self.span_to_tts(span).into_iter();
+ let mut toks = self.retokenise_span(span);
+ toks.real_token();
+ let mut toks = toks.parse_all_token_trees().unwrap().into_iter();
let mut prev = toks.next().unwrap();
+
let first_span = prev.get_span();
let mut angle_count = 0;
for tok in toks {
}
let next = toks.real_token();
if next.tok == tok {
- return self.make_sub_span(span, Some(prev.sp));
+ return Some(prev.sp);
}
prev = next;
}
return None;
}
if next.tok == tok {
- return self.make_sub_span(span, Some(next.sp));
+ return Some(next.sp);
}
}
}
if ts.tok == token::Eof {
return None
} else {
- return self.make_sub_span(span, Some(ts.sp));
+ return Some(ts.sp);
}
}
}
if ts.tok == token::Not {
let ts = toks.real_token();
if ts.tok.is_ident() {
- return self.make_sub_span(span, Some(ts.sp));
+ return Some(ts.sp);
} else {
return None;
}
let ts = toks.real_token();
if ts.tok == token::Not {
if prev.tok.is_ident() {
- return self.make_sub_span(span, Some(prev.sp));
+ return Some(prev.sp);
} else {
return None;
}
impl FnType {
pub fn new<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- abi: Abi,
- sig: &ty::FnSig<'tcx>,
+ sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
- let mut fn_ty = FnType::unadjusted(ccx, abi, sig, extra_args);
- fn_ty.adjust_for_abi(ccx, abi, sig);
+ let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
+ fn_ty.adjust_for_abi(ccx, sig);
fn_ty
}
pub fn unadjusted<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- abi: Abi,
- sig: &ty::FnSig<'tcx>,
+ sig: ty::FnSig<'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
use self::Abi::*;
- let cconv = match ccx.sess().target.target.adjust_abi(abi) {
+ let cconv = match ccx.sess().target.target.adjust_abi(sig.abi) {
RustIntrinsic | PlatformIntrinsic |
Rust | RustCall => llvm::CCallConv,
};
let mut inputs = sig.inputs();
- let extra_args = if abi == RustCall {
+ let extra_args = if sig.abi == RustCall {
assert!(!sig.variadic && extra_args.is_empty());
match sig.inputs().last().unwrap().sty {
let linux_s390x = target.target_os == "linux"
&& target.arch == "s390x"
&& target.target_env == "gnu";
- let rust_abi = match abi {
+ let rust_abi = match sig.abi {
RustIntrinsic | PlatformIntrinsic | Rust | RustCall => true,
_ => false
};
if let Some(inner) = rust_ptr_attrs(ty, &mut data) {
data.attrs.set(ArgAttribute::NonNull);
if ccx.tcx().struct_tail(inner).is_trait() {
+ // vtables can be safely marked non-null, readonly
+ // and noalias.
info.attrs.set(ArgAttribute::NonNull);
+ info.attrs.set(ArgAttribute::ReadOnly);
+ info.attrs.set(ArgAttribute::NoAlias);
}
}
args.push(data);
pub fn adjust_for_abi<'a, 'tcx>(&mut self,
ccx: &CrateContext<'a, 'tcx>,
- abi: Abi,
- sig: &ty::FnSig<'tcx>) {
+ sig: ty::FnSig<'tcx>) {
+ let abi = sig.abi;
if abi == Abi::Unadjusted { return }
if abi == Abi::Rust || abi == Abi::RustCall ||
use session::config::{self, NoDebugInfo};
use rustc_incremental::IncrementalHashesMap;
use session::{self, DataTypeKind, Session};
-use abi::{self, Abi, FnType};
+use abi::{self, FnType};
use mir::lvalue::LvalueRef;
use adt;
use attributes;
b.load(ptr, alignment.to_align())
};
- // FIXME: emit metadata on `meta`.
- let meta = b.load(get_meta(b, src), alignment.to_align());
+ let meta = get_meta(b, src);
+ let meta_ty = val_ty(meta);
+ // If the 'meta' field is a pointer, it's a vtable, so use load_nonnull
+ // instead
+ let meta = if meta_ty.element_type().kind() == llvm::TypeKind::Pointer {
+ b.load_nonnull(meta, None)
+ } else {
+ b.load(meta, None)
+ };
(ptr, meta)
}
let fn_ty = ccx.tcx().erase_regions(&fn_ty);
let fn_ty = monomorphize::apply_param_substs(ccx.shared(), instance.substs, &fn_ty);
- let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_ty);
- let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
+ let sig = common::ty_fn_sig(ccx, fn_ty);
+ let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
let lldecl = match ccx.instances().borrow().get(&instance) {
Some(&val) => val,
attributes::emit_uwtable(lldecl, true);
}
- let fn_ty = FnType::new(ccx, abi, &sig, &[]);
-
let mir = ccx.tcx().item_mir(instance.def);
- mir::trans_mir(ccx, lldecl, fn_ty, &mir, instance, &sig, abi);
+ mir::trans_mir(ccx, lldecl, &mir, instance, sig);
}
pub fn trans_ctor_shim<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
let ctor_ty = monomorphize::apply_param_substs(ccx.shared(), substs, &ctor_ty);
let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&ctor_ty.fn_sig());
- let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
+ let fn_ty = FnType::new(ccx, sig, &[]);
let bcx = Builder::new_block(ccx, llfn, "entry-block");
if !fn_ty.ret.is_ignore() {
let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis;
let exported_symbols = find_exported_symbols(tcx, reachable);
- let check_overflow = if let Some(v) = tcx.sess.opts.debugging_opts.force_overflow_checks {
- v
- } else {
- tcx.sess.opts.debug_assertions
- };
+ let check_overflow = tcx.sess.overflow_checks();
let link_meta = link::build_link_meta(incremental_hashes_map, &name);
}
}
+ pub fn set_invariant_load(&self, load: ValueRef) {
+ unsafe {
+ llvm::LLVMSetMetadata(load, llvm::MD_invariant_load as c_uint,
+ llvm::LLVMMDNodeInContext(self.ccx.llcx(), ptr::null(), 0));
+ }
+ }
+
/// Returns the ptr value that should be used for storing `val`.
fn check_store<'b>(&self,
val: ValueRef,
}
assert!(fn_ty.kind() == llvm::TypeKind::Function,
- "builder::{} not passed a function", typ);
+ "builder::{} not passed a function, but {:?}", typ, fn_ty);
let param_tys = fn_ty.func_params();
use llvm::{self, ValueRef, get_params};
use rustc::hir::def_id::DefId;
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Substs, Subst};
use rustc::traits;
use abi::{Abi, FnType};
use attributes;
let fn_ty = def_ty(ccx.shared(), def_id, substs);
if let ty::TyFnDef(.., f) = fn_ty.sty {
- if f.abi == Abi::RustIntrinsic || f.abi == Abi::PlatformIntrinsic {
+ if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
return Callee {
data: Intrinsic,
ty: fn_ty
// FIXME(eddyb) Detect ADT constructors more efficiently.
if let Some(adt_def) = fn_ty.fn_ret().skip_binder().ty_adt_def() {
- if let Some(v) = adt_def.variants.iter().find(|v| def_id == v.did) {
+ if let Some(i) = adt_def.variants.iter().position(|v| def_id == v.did) {
return Callee {
- data: NamedTupleConstructor(Disr::from(v.disr_val)),
+ data: NamedTupleConstructor(Disr::for_variant(tcx, adt_def, i)),
ty: fn_ty
};
}
/// The extra argument types are for variadic (extern "C") functions.
pub fn direct_fn_type<'a>(&self, ccx: &CrateContext<'a, 'tcx>,
extra_args: &[Ty<'tcx>]) -> FnType {
- let abi = self.ty.fn_abi();
- let sig = ccx.tcx().erase_late_bound_regions_and_normalize(self.ty.fn_sig());
- let mut fn_ty = FnType::unadjusted(ccx, abi, &sig, extra_args);
+ let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&self.ty.fn_sig());
+ let mut fn_ty = FnType::unadjusted(ccx, sig, extra_args);
if let Virtual(_) = self.data {
// Don't pass the vtable, it's not an argument of the virtual fn.
fn_ty.args[1].ignore();
}
- fn_ty.adjust_for_abi(ccx, abi, &sig);
+ fn_ty.adjust_for_abi(ccx, sig);
fn_ty
}
let ref_closure_ty = tcx.mk_imm_ref(tcx.mk_region(ty::ReErased), closure_ty);
// Make a version with the type of by-ref closure.
- let ty::ClosureTy { unsafety, abi, mut sig } = tcx.closure_type(def_id, substs);
- sig.0 = tcx.mk_fn_sig(
- iter::once(ref_closure_ty).chain(sig.0.inputs().iter().cloned()),
- sig.0.output(),
- sig.0.variadic
- );
- let llref_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: unsafety,
- abi: abi,
- sig: sig.clone()
- }));
+ let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
+ let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
+ assert_eq!(sig.abi, Abi::RustCall);
+ let llref_fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+ iter::once(ref_closure_ty).chain(sig.inputs().iter().cloned()),
+ sig.output(),
+ sig.variadic,
+ sig.unsafety,
+ Abi::RustCall
+ )));
debug!("trans_fn_once_adapter_shim: llref_fn_ty={:?}",
llref_fn_ty);
// Make a version of the closure type with the same arguments, but
// with argument #0 being by value.
- assert_eq!(abi, Abi::RustCall);
- sig.0 = tcx.mk_fn_sig(
- iter::once(closure_ty).chain(sig.0.inputs().iter().skip(1).cloned()),
- sig.0.output(),
- sig.0.variadic
+ let sig = tcx.mk_fn_sig(
+ iter::once(closure_ty).chain(sig.inputs().iter().cloned()),
+ sig.output(),
+ sig.variadic,
+ sig.unsafety,
+ Abi::RustCall
);
- let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
- let fn_ty = FnType::new(ccx, abi, &sig, &[]);
-
- let llonce_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: unsafety,
- abi: abi,
- sig: ty::Binder(sig)
- }));
+ let fn_ty = FnType::new(ccx, sig, &[]);
+ let llonce_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
// Create the by-value helper.
let function_name = method_instance.symbol_name(ccx.shared());
// Construct the "tuply" version of `bare_fn_ty`. It takes two arguments: `self`,
// which is the fn pointer, and `args`, which is the arguments tuple.
- let sig = match bare_fn_ty.sty {
- ty::TyFnDef(..,
- &ty::BareFnTy { unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- ref sig }) |
- ty::TyFnPtr(&ty::BareFnTy { unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- ref sig }) => sig,
-
- _ => {
- bug!("trans_fn_pointer_shim invoked on invalid type: {}",
- bare_fn_ty);
- }
- };
- let sig = tcx.erase_late_bound_regions_and_normalize(sig);
+ let sig = bare_fn_ty.fn_sig();
+ let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
+ assert_eq!(sig.unsafety, hir::Unsafety::Normal);
+ assert_eq!(sig.abi, Abi::Rust);
let tuple_input_ty = tcx.intern_tup(sig.inputs(), false);
let sig = tcx.mk_fn_sig(
[bare_fn_ty_maybe_ref, tuple_input_ty].iter().cloned(),
sig.output(),
- false
+ false,
+ hir::Unsafety::Normal,
+ Abi::RustCall
);
- let fn_ty = FnType::new(ccx, Abi::RustCall, &sig, &[]);
- let tuple_fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Normal,
- abi: Abi::RustCall,
- sig: ty::Binder(sig)
- }));
+ let fn_ty = FnType::new(ccx, sig, &[]);
+ let tuple_fn_ty = tcx.mk_fn_ptr(ty::Binder(sig));
debug!("tuple_fn_ty: {:?}", tuple_fn_ty);
//
// other weird situations. Annoying.
// Create a fn pointer with the substituted signature.
- let fn_ptr_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(common::ty_fn_ty(ccx, fn_ty).into_owned()));
+ let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(ccx, fn_ty));
let llptrty = type_of::type_of(ccx, fn_ptr_ty);
let llfn = if let Some(llfn) = declare::get_declared_value(ccx, &sym) {
self.output);
}
}
+ mir::Rvalue::Cast(mir::CastKind::ClosureFnPointer, ref operand, _) => {
+ let source_ty = operand.ty(self.mir, self.scx.tcx());
+ match source_ty.sty {
+ ty::TyClosure(def_id, substs) => {
+ let closure_trans_item =
+ create_fn_trans_item(self.scx,
+ def_id,
+ substs.substs,
+ self.param_substs);
+ self.output.push(closure_trans_item);
+ }
+ _ => bug!(),
+ }
+ }
mir::Rvalue::Box(..) => {
let exchange_malloc_fn_def_id =
self.scx
def_id: DefId)
-> bool {
match tcx.item_type(def_id).sty {
- ty::TyFnDef(def_id, _, f) => {
+ ty::TyFnDef(def_id, _, _) => {
// Some constructors also have type TyFnDef but they are
// always instantiated inline and don't result in a
// translation item. Same for FFI functions.
if let Some(hir_map::NodeForeignItem(_)) = tcx.hir.get_if_local(def_id) {
return false;
}
-
- if let Some(adt_def) = f.sig.output().skip_binder().ty_adt_def() {
- if adt_def.variants.iter().any(|v| def_id == v.did) {
- return false;
- }
- }
}
ty::TyClosure(..) => {}
_ => return false
fn is_drop_in_place_intrinsic<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
- bare_fn_ty: &ty::BareFnTy<'tcx>)
+ bare_fn_ty: ty::PolyFnSig<'tcx>)
-> bool {
- (bare_fn_ty.abi == Abi::RustIntrinsic ||
- bare_fn_ty.abi == Abi::PlatformIntrinsic) &&
+ (bare_fn_ty.abi() == Abi::RustIntrinsic ||
+ bare_fn_ty.abi() == Abi::PlatformIntrinsic) &&
tcx.item_name(def_id) == "drop_in_place"
}
}
fn should_trans_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId)
-> bool {
+ if let ty::TyFnDef(_, _, sig) = tcx.item_type(def_id).sty {
+ if let Some(adt_def) = sig.output().skip_binder().ty_adt_def() {
+ if adt_def.variants.iter().any(|v| def_id == v.did) {
+ // HACK: ADT constructors are translated in-place and
+ // do not have a trans-item.
+ return false;
+ }
+ }
+ }
+
if def_id.is_local() {
true
} else {
// If the type implements Drop, also add a translation item for the
// monomorphized Drop::drop() implementation.
let destructor_did = match ty.sty {
- ty::TyAdt(def, _) => def.destructor(),
+ ty::TyAdt(def, _) => def.destructor(scx.tcx()),
_ => None
};
use value::Value;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::layout::Layout;
+use rustc::ty::subst::Subst;
use rustc::traits::{self, SelectionContext, Reveal};
use rustc::hir;
use libc::{c_uint, c_char};
-use std::borrow::Cow;
use std::iter;
use syntax::ast;
}
}
-pub fn ty_fn_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
- ty: Ty<'tcx>)
- -> Cow<'tcx, ty::BareFnTy<'tcx>>
+pub fn ty_fn_sig<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ ty: Ty<'tcx>)
+ -> ty::PolyFnSig<'tcx>
{
match ty.sty {
- ty::TyFnDef(_, _, fty) => Cow::Borrowed(fty),
+ ty::TyFnDef(_, _, sig) => sig,
// Shims currently have type TyFnPtr. Not sure this should remain.
- ty::TyFnPtr(fty) => Cow::Borrowed(fty),
+ ty::TyFnPtr(sig) => sig,
ty::TyClosure(def_id, substs) => {
let tcx = ccx.tcx();
- let ty::ClosureTy { unsafety, abi, sig } = tcx.closure_type(def_id, substs);
+ let sig = tcx.closure_type(def_id).subst(tcx, substs.substs);
let env_region = ty::ReLateBound(ty::DebruijnIndex::new(1), ty::BrEnv);
let env_ty = match tcx.closure_kind(def_id) {
ty::ClosureKind::FnOnce => ty,
};
- let sig = sig.map_bound(|sig| tcx.mk_fn_sig(
+ sig.map_bound(|sig| tcx.mk_fn_sig(
iter::once(env_ty).chain(sig.inputs().iter().cloned()),
sig.output(),
- sig.variadic
- ));
- Cow::Owned(ty::BareFnTy { unsafety: unsafety, abi: abi, sig: sig })
+ sig.variadic,
+ sig.unsafety,
+ sig.abi
+ ))
}
_ => bug!("unexpected type {:?} to ty_fn_sig", ty)
}
g
}
-pub fn trans_static(ccx: &CrateContext,
- m: hir::Mutability,
- id: ast::NodeId,
- attrs: &[ast::Attribute])
- -> Result<ValueRef, ConstEvalErr> {
+pub fn trans_static<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
+ m: hir::Mutability,
+ id: ast::NodeId,
+ attrs: &[ast::Attribute])
+ -> Result<ValueRef, ConstEvalErr<'tcx>> {
unsafe {
let def_id = ccx.tcx().hir.local_def_id(id);
let g = get_static(ccx, def_id);
return llfn;
}
- let ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Unsafe,
- abi: Abi::C,
- sig: ty::Binder(tcx.mk_fn_sig(
- iter::once(tcx.mk_mut_ptr(tcx.types.u8)),
- tcx.types.never,
- false
- )),
- }));
+ let ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+ iter::once(tcx.mk_mut_ptr(tcx.types.u8)),
+ tcx.types.never,
+ false,
+ hir::Unsafety::Unsafe,
+ Abi::C
+ )));
let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty);
attributes::unwind(llfn, true);
fn subroutine_type_metadata<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
unique_type_id: UniqueTypeId,
- signature: &ty::PolyFnSig<'tcx>,
+ signature: ty::PolyFnSig<'tcx>,
span: Span)
-> MetadataCreationResult
{
- let signature = cx.tcx().erase_late_bound_regions(signature);
+ let signature = cx.tcx().erase_late_bound_regions(&signature);
let mut signature_metadata: Vec<DIType> = Vec::with_capacity(signature.inputs().len() + 1);
Err(metadata) => return metadata,
}
}
- ty::TyFnDef(.., ref barefnty) | ty::TyFnPtr(ref barefnty) => {
+ ty::TyFnDef(.., sig) | ty::TyFnPtr(sig) => {
let fn_metadata = subroutine_type_metadata(cx,
unique_type_id,
- &barefnty.sig,
+ sig,
usage_site_span).metadata;
match debug_context(cx).type_map
.borrow()
// <unknown>
let file_metadata = unknown_file_metadata(cx);
- let variants = &enum_type.ty_adt_def().unwrap().variants;
- let enumerators_metadata: Vec<DIDescriptor> = variants
- .iter()
- .map(|v| {
+ let def = enum_type.ty_adt_def().unwrap();
+ let enumerators_metadata: Vec<DIDescriptor> = def.discriminants(cx.tcx())
+ .zip(&def.variants)
+ .map(|(discr, v)| {
let token = v.name.as_str();
let name = CString::new(token.as_bytes()).unwrap();
unsafe {
DIB(cx),
name.as_ptr(),
// FIXME: what if enumeration has i128 discriminant?
- v.disr_val as u64)
+ discr.to_u128_unchecked() as u64)
}
})
.collect();
/// for the function.
pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
instance: Instance<'tcx>,
- sig: &ty::FnSig<'tcx>,
- abi: Abi,
+ sig: ty::FnSig<'tcx>,
llfn: ValueRef,
mir: &mir::Mir) -> FunctionDebugContext {
if cx.sess().opts.debuginfo == NoDebugInfo {
let file_metadata = file_metadata(cx, &loc.file.name, &loc.file.abs_path);
let function_type_metadata = unsafe {
- let fn_signature = get_function_signature(cx, sig, abi);
+ let fn_signature = get_function_signature(cx, sig);
llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), file_metadata, fn_signature)
};
return FunctionDebugContext::RegularContext(fn_debug_context);
fn get_function_signature<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
- sig: &ty::FnSig<'tcx>,
- abi: Abi) -> DIArray {
+ sig: ty::FnSig<'tcx>) -> DIArray {
if cx.sess().opts.debuginfo == LimitedDebugInfo {
return create_DIArray(DIB(cx), &[]);
}
_ => type_metadata(cx, sig.output(), syntax_pos::DUMMY_SP)
});
- let inputs = if abi == Abi::RustCall {
+ let inputs = if sig.abi == Abi::RustCall {
&sig.inputs()[..sig.inputs().len() - 1]
} else {
sig.inputs()
signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
}
- if abi == Abi::RustCall && !sig.inputs().is_empty() {
+ if sig.abi == Abi::RustCall && !sig.inputs().is_empty() {
if let ty::TyTuple(args, _) = sig.inputs()[sig.inputs().len() - 1].sty {
for &argument_type in args {
signature.push(type_metadata(cx, argument_type, syntax_pos::DUMMY_SP));
}
fn get_template_parameters<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
- generics: &ty::Generics<'tcx>,
+ generics: &ty::Generics,
substs: &Substs<'tcx>,
file_metadata: DIFile,
name_to_append_suffix_to: &mut String)
return create_DIArray(DIB(cx), &template_params[..]);
}
- fn get_type_parameter_names<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
- generics: &ty::Generics<'tcx>)
- -> Vec<ast::Name> {
+ fn get_type_parameter_names(cx: &CrateContext, generics: &ty::Generics) -> Vec<ast::Name> {
let mut names = generics.parent.map_or(vec![], |def_id| {
get_type_parameter_names(cx, cx.tcx().item_generics(def_id))
});
push_type_params(cx, principal.substs, output);
}
},
- ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
- ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
- if unsafety == hir::Unsafety::Unsafe {
+ ty::TyFnDef(.., sig) |
+ ty::TyFnPtr(sig) => {
+ if sig.unsafety() == hir::Unsafety::Unsafe {
output.push_str("unsafe ");
}
+ let abi = sig.abi();
if abi != ::abi::Abi::Rust {
output.push_str("extern \"");
output.push_str(abi.name());
output.push_str("fn(");
- let sig = cx.tcx().erase_late_bound_regions_and_normalize(sig);
+ let sig = cx.tcx().erase_late_bound_regions_and_normalize(&sig);
if !sig.inputs().is_empty() {
for ¶meter_type in sig.inputs() {
push_debuginfo_type_name(cx, parameter_type, true, output);
use super::namespace::item_namespace;
use rustc::hir::def_id::DefId;
+use rustc::ty::DefIdTree;
use llvm;
use llvm::debuginfo::{DIScope, DIBuilderRef, DIDescriptor, DIArray};
pub fn get_namespace_and_span_for_item(cx: &CrateContext, def_id: DefId)
-> (DIScope, Span) {
- let containing_scope = item_namespace(cx, DefId {
- krate: def_id.krate,
- index: cx.tcx().def_key(def_id).parent
- .expect("get_namespace_and_span_for_item: missing parent?")
- });
+ let containing_scope = item_namespace(cx, cx.tcx().parent(def_id)
+ .expect("get_namespace_and_span_for_item: missing parent?"));
// Try to get some span information, if we have an inlined item.
let definition_span = cx.tcx().def_span(def_id);
pub fn declare_fn<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, name: &str,
fn_type: ty::Ty<'tcx>) -> ValueRef {
debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
- let ty::BareFnTy { abi, ref sig, .. } = *common::ty_fn_ty(ccx, fn_type);
- let sig = ccx.tcx().erase_late_bound_regions_and_normalize(sig);
+ let sig = common::ty_fn_sig(ccx, fn_type);
+ let sig = ccx.tcx().erase_late_bound_regions_and_normalize(&sig);
debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
- let fty = FnType::new(ccx, abi, &sig, &[]);
+ let fty = FnType::new(ccx, sig, &[]);
let llfn = declare_raw_fn(ccx, name, fty.cconv, fty.llvm_type(ccx));
// FIXME(canndrew): This is_never should really be an is_uninhabited
llvm::Attribute::NoReturn.apply_llfn(Function, llfn);
}
- if abi != Abi::Rust && abi != Abi::RustCall {
+ if sig.abi != Abi::Rust && sig.abi != Abi::RustCall {
attributes::unwind(llfn, false);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use rustc::middle::const_val::ConstVal;
+use rustc::ty::{self, TyCtxt};
+use rustc_const_math::ConstInt;
+
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
pub struct Disr(pub u64);
impl Disr {
+ pub fn for_variant(tcx: TyCtxt,
+ def: &ty::AdtDef,
+ variant_index: usize) -> Self {
+ let mut explicit_index = variant_index;
+ let mut explicit_value = Disr(0);
+ loop {
+ match def.variants[explicit_index].discr {
+ ty::VariantDiscr::Relative(0) => break,
+ ty::VariantDiscr::Relative(distance) => {
+ explicit_index -= distance;
+ }
+ ty::VariantDiscr::Explicit(expr_did) => {
+ match tcx.maps.monomorphic_const_eval.borrow()[&expr_did] {
+ Ok(ConstVal::Integral(v)) => {
+ explicit_value = Disr::from(v);
+ break;
+ }
+ _ => {
+ explicit_index -= 1;
+ }
+ }
+ }
+ }
+ }
+ let distance = variant_index - explicit_index;
+ explicit_value.wrapping_add(Disr::from(distance))
+ }
+
pub fn wrapping_add(self, other: Self) -> Self {
Disr(self.0.wrapping_add(other.0))
}
}
}
-impl From<::rustc::ty::Disr> for Disr {
- fn from(i: ::rustc::ty::Disr) -> Disr {
+impl From<ConstInt> for Disr {
+ fn from(i: ConstInt) -> Disr {
// FIXME: what if discr has 128 bit discr?
- Disr(i as u64)
+ Disr(i.to_u128_unchecked() as u64)
}
}
bcx.call(dtor, &[ptr.llval], None);
bcx
}
- ty::TyAdt(def, ..) if def.has_dtor() && !skip_dtor => {
+ ty::TyAdt(def, ..) if def.has_dtor(bcx.tcx()) && !skip_dtor => {
let shallow_drop = def.is_union();
let tcx = bcx.tcx();
traits::VtableImpl(data) => data,
_ => bug!("dtor for {:?} is not an impl???", t)
};
- let dtor_did = def.destructor().unwrap();
+ let dtor_did = def.destructor(tcx).unwrap();
let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
let llret;
let info = bcx.pointercast(info, Type::int(bcx.ccx).ptr_to());
let size_ptr = bcx.gepi(info, &[1]);
let align_ptr = bcx.gepi(info, &[2]);
- (bcx.load(size_ptr, None), bcx.load(align_ptr, None))
+
+ let size = bcx.load(size_ptr, None);
+ let align = bcx.load(align_ptr, None);
+
+ // Vtable loads are invariant
+ bcx.set_invariant_load(size);
+ bcx.set_invariant_load(align);
+
+ (size, align)
}
ty::TySlice(_) | ty::TyStr => {
let unit_ty = t.sequence_element_type(bcx.tcx());
let llswitch = cx.switch(lldiscrim_a, ret_void_cx.llbb(), n_variants);
let next_cx = cx.build_sibling_block("enum-iter-next");
- for (i, variant) in adt.variants.iter().enumerate() {
- let variant_cx_name = format!("enum-iter-variant-{}",
- &variant.disr_val.to_string());
+ for (i, discr) in adt.discriminants(cx.tcx()).enumerate() {
+ let variant_cx_name = format!("enum-iter-variant-{}", i);
let variant_cx = cx.build_sibling_block(&variant_cx_name);
- let case_val = adt::trans_case(&cx, t, Disr::from(variant.disr_val));
+ let case_val = adt::trans_case(&cx, t, Disr::from(discr));
variant_cx.add_case(llswitch, case_val, variant_cx.llbb());
ptr.ty = LvalueTy::Downcast {
adt_def: adt,
let ccx = bcx.ccx;
let tcx = ccx.tcx();
- let (def_id, substs, fty) = match callee_ty.sty {
- ty::TyFnDef(def_id, substs, ref fty) => (def_id, substs, fty),
+ let (def_id, substs, sig) = match callee_ty.sty {
+ ty::TyFnDef(def_id, substs, sig) => (def_id, substs, sig),
_ => bug!("expected fn item type, found {}", callee_ty)
};
- let sig = tcx.erase_late_bound_regions_and_normalize(&fty.sig);
+ let sig = tcx.erase_late_bound_regions_and_normalize(&sig);
let arg_tys = sig.inputs();
let ret_ty = sig.output();
let name = &*tcx.item_name(def_id).as_str();
output: Ty<'tcx>,
trans: &mut for<'b> FnMut(Builder<'b, 'tcx>))
-> ValueRef {
- let sig = ccx.tcx().mk_fn_sig(inputs.into_iter(), output, false);
-
- let rust_fn_ty = ccx.tcx().mk_fn_ptr(ccx.tcx().mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Unsafe,
- abi: Abi::Rust,
- sig: ty::Binder(sig)
- }));
+ let rust_fn_ty = ccx.tcx().mk_fn_ptr(ty::Binder(ccx.tcx().mk_fn_sig(
+ inputs.into_iter(),
+ output,
+ false,
+ hir::Unsafety::Unsafe,
+ Abi::Rust
+ )));
let llfn = declare::define_internal_fn(ccx, name, rust_fn_ty);
let bcx = Builder::new_block(ccx, llfn, "entry-block");
trans(bcx);
// Define the type up front for the signature of the rust_try function.
let tcx = ccx.tcx();
let i8p = tcx.mk_mut_ptr(tcx.types.i8);
- let fn_ty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Unsafe,
- abi: Abi::Rust,
- sig: ty::Binder(tcx.mk_fn_sig(iter::once(i8p), tcx.mk_nil(), false)),
- }));
+ let fn_ty = tcx.mk_fn_ptr(ty::Binder(tcx.mk_fn_sig(
+ iter::once(i8p),
+ tcx.mk_nil(),
+ false,
+ hir::Unsafety::Unsafe,
+ Abi::Rust
+ )));
let output = tcx.types.i32;
let rust_try = gen_fn(ccx, "__rust_try", vec![fn_ty, i8p, i8p], output, trans);
ccx.rust_try_fn().set(Some(rust_try));
let tcx = bcx.tcx();
- let sig = tcx.erase_late_bound_regions_and_normalize(callee_ty.fn_sig());
+ let sig = tcx.erase_late_bound_regions_and_normalize(&callee_ty.fn_sig());
let arg_tys = sig.inputs();
// every intrinsic takes a SIMD vector as its first argument
/// Extracts a method from a trait object's vtable, at the specified index.
pub fn get_virtual_method<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
llvtable: ValueRef,
- vtable_index: usize)
- -> ValueRef {
+ vtable_index: usize) -> ValueRef {
// Load the data pointer from the object.
debug!("get_virtual_method(vtable_index={}, llvtable={:?})",
vtable_index, Value(llvtable));
- bcx.load(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]), None)
+ let ptr = bcx.load_nonnull(bcx.gepi(llvtable, &[vtable_index + VTABLE_OFFSET]), None);
+ // Vtable loads are invariant
+ bcx.set_invariant_load(ptr);
+ ptr
}
/// Generate a shim function that allows an object type like `SomeTrait` to
if switch_ty == bcx.tcx().types.bool {
let lltrue = llblock(self, targets[0]);
let llfalse = llblock(self, targets[1]);
- if let [ConstInt::Infer(0)] = values[..] {
+ if let [ConstInt::U8(0)] = values[..] {
bcx.cond_br(discr.immediate(), llfalse, lltrue);
} else {
bcx.cond_br(discr.immediate(), lltrue, llfalse);
// Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar.
let callee = self.trans_operand(&bcx, func);
- let (mut callee, abi, sig) = match callee.ty.sty {
- ty::TyFnDef(def_id, substs, f) => {
- (Callee::def(bcx.ccx, def_id, substs), f.abi, &f.sig)
+ let (mut callee, sig) = match callee.ty.sty {
+ ty::TyFnDef(def_id, substs, sig) => {
+ (Callee::def(bcx.ccx, def_id, substs), sig)
}
- ty::TyFnPtr(f) => {
+ ty::TyFnPtr(sig) => {
(Callee {
data: Fn(callee.immediate()),
ty: callee.ty
- }, f.abi, &f.sig)
+ }, sig)
}
_ => bug!("{} is not callable", callee.ty)
};
- let sig = bcx.tcx().erase_late_bound_regions_and_normalize(sig);
+ let sig = bcx.tcx().erase_late_bound_regions_and_normalize(&sig);
+ let abi = sig.abi;
// Handle intrinsics old trans wants Expr's for, ourselves.
let intrinsic = match (&callee.ty.sty, &callee.data) {
use rustc::mir::tcx::LvalueTy;
use rustc::ty::{self, layout, Ty, TyCtxt, TypeFoldable};
use rustc::ty::cast::{CastTy, IntTy};
-use rustc::ty::subst::Substs;
+use rustc::ty::subst::{Kind, Substs, Subst};
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
use {abi, adt, base, Disr, machine};
use callee::Callee;
let u = v.as_u64(ccx.tcx().sess.target.uint_type);
(C_integral(Type::int(ccx), u, false), tcx.types.usize)
},
- Infer(_) | InferSigned(_) => bug!("MIR must not use `{:?}`", ci),
};
Const { llval: llval, ty: ty }
}
let val = match cv {
ConstVal::Float(F32(v)) => C_floating_f64(v as f64, llty),
ConstVal::Float(F64(v)) => C_floating_f64(v, llty),
- ConstVal::Float(FInfer {..}) => bug!("MIR must not use `{:?}`", cv),
ConstVal::Bool(v) => C_bool(ccx, v),
ConstVal::Integral(ref i) => return Const::from_constint(ccx, i),
ConstVal::Str(ref v) => C_str_slice(ccx, v.clone()),
ConstVal::ByteStr(ref v) => consts::addr_of(ccx, C_bytes(ccx, v), 1, "byte_str"),
ConstVal::Struct(_) | ConstVal::Tuple(_) |
ConstVal::Array(..) | ConstVal::Repeat(..) |
- ConstVal::Function(_) => {
+ ConstVal::Function(..) => {
bug!("MIR must not use `{:?}` (which refers to a local ID)", cv)
}
ConstVal::Char(c) => C_integral(Type::char(ccx), c as u64, false),
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
instance: Instance<'tcx>,
args: IndexVec<mir::Local, Const<'tcx>>)
- -> Result<Const<'tcx>, ConstEvalErr> {
+ -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
let instance = instance.resolve_const(ccx.shared());
let mir = ccx.tcx().item_mir(instance.def);
MirConstContext::new(ccx, &mir, instance.substs, args).trans()
value)
}
- fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr> {
+ fn trans(&mut self) -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
let tcx = self.ccx.tcx();
let mut bb = mir::START_BLOCK;
};
let err = ConstEvalErr{ span: span, kind: err };
- report_const_eval_err(tcx, &err, span, "expression").emit();
+ report_const_eval_err(tcx, &err, span, "expression");
failure = Err(err);
}
target
}
fn const_lvalue(&self, lvalue: &mir::Lvalue<'tcx>, span: Span)
- -> Result<ConstLvalue<'tcx>, ConstEvalErr> {
+ -> Result<ConstLvalue<'tcx>, ConstEvalErr<'tcx>> {
let tcx = self.ccx.tcx();
if let mir::Lvalue::Local(index) = *lvalue {
}
fn const_operand(&self, operand: &mir::Operand<'tcx>, span: Span)
- -> Result<Const<'tcx>, ConstEvalErr> {
+ -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
debug!("const_operand({:?} @ {:?})", operand, span);
let result = match *operand {
mir::Operand::Consume(ref lvalue) => {
fn const_rvalue(&self, rvalue: &mir::Rvalue<'tcx>,
dest_ty: Ty<'tcx>, span: Span)
- -> Result<Const<'tcx>, ConstEvalErr> {
+ -> Result<Const<'tcx>, ConstEvalErr<'tcx>> {
let tcx = self.ccx.tcx();
debug!("const_rvalue({:?}: {:?} @ {:?})", rvalue, dest_ty, span);
let val = match *rvalue {
}
}
}
+ mir::CastKind::ClosureFnPointer => {
+ match operand.ty.sty {
+ ty::TyClosure(def_id, substs) => {
+ // Get the def_id for FnOnce::call_once
+ let fn_once = tcx.lang_items.fn_once_trait().unwrap();
+ let call_once = tcx
+ .global_tcx().associated_items(fn_once)
+ .find(|it| it.kind == ty::AssociatedKind::Method)
+ .unwrap().def_id;
+ // Now create its substs [Closure, Tuple]
+ let input = tcx.closure_type(def_id)
+ .subst(tcx, substs.substs).input(0);
+ let substs = tcx.mk_substs([operand.ty, input.skip_binder()]
+ .iter().cloned().map(Kind::from));
+ Callee::def(self.ccx, call_once, substs)
+ .reify(self.ccx)
+ }
+ _ => {
+ bug!("{} cannot be cast to a fn ptr", operand.ty)
+ }
+ }
+ }
mir::CastKind::UnsafeFnPointer => {
// this is a no-op at the LLVM level
operand.llval
}
-pub fn trans_static_initializer(ccx: &CrateContext, def_id: DefId)
- -> Result<ValueRef, ConstEvalErr> {
+pub fn trans_static_initializer<'a, 'tcx>(
+ ccx: &CrateContext<'a, 'tcx>,
+ def_id: DefId)
+ -> Result<ValueRef, ConstEvalErr<'tcx>>
+{
let instance = Instance::mono(ccx.shared(), def_id);
MirConstContext::trans_def(ccx, instance, IndexVec::new()).map(|c| c.llval)
}
layout::CEnum { discr: d, min, max, .. } => {
let discr = match *kind {
mir::AggregateKind::Adt(adt_def, _, _, _) => {
- Disr::from(adt_def.variants[variant_index].disr_val)
+ Disr::for_variant(ccx.tcx(), adt_def, variant_index)
},
_ => Disr(0),
};
use syntax_pos::{DUMMY_SP, NO_EXPANSION, COMMAND_LINE_EXPN, BytePos, Span};
use syntax::symbol::keywords;
-use syntax::abi::Abi;
use std::iter;
pub fn trans_mir<'a, 'tcx: 'a>(
ccx: &'a CrateContext<'a, 'tcx>,
llfn: ValueRef,
- fn_ty: FnType,
mir: &'a Mir<'tcx>,
instance: Instance<'tcx>,
- sig: &ty::FnSig<'tcx>,
- abi: Abi,
+ sig: ty::FnSig<'tcx>,
) {
+ let fn_ty = FnType::new(ccx, sig, &[]);
debug!("fn_ty: {:?}", fn_ty);
let debug_context =
- debuginfo::create_function_debug_context(ccx, instance, sig, abi, llfn, mir);
+ debuginfo::create_function_debug_context(ccx, instance, sig, llfn, mir);
let bcx = Builder::new_block(ccx, llfn, "entry-block");
let cleanup_kinds = analyze::cleanup_kinds(&mir);
use rustc::ty::{self, Ty};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::layout::Layout;
+use rustc::ty::subst::{Kind, Subst};
use rustc::mir::tcx::LvalueTy;
use rustc::mir;
use middle::lang_items::ExchangeMallocFnLangItem;
mir::Rvalue::Aggregate(ref kind, ref operands) => {
match *kind {
mir::AggregateKind::Adt(adt_def, variant_index, substs, active_field_index) => {
- let disr = Disr::from(adt_def.variants[variant_index].disr_val);
+ let disr = Disr::for_variant(bcx.tcx(), adt_def, variant_index);
let dest_ty = dest.ty.to_ty(bcx.tcx());
- adt::trans_set_discr(&bcx, dest_ty, dest.llval, Disr::from(disr));
+ adt::trans_set_discr(&bcx, dest_ty, dest.llval, disr);
for (i, operand) in operands.iter().enumerate() {
let op = self.trans_operand(&bcx, operand);
// Do not generate stores and GEPis for zero-sized fields.
val.ty = LvalueTy::Downcast {
adt_def: adt_def,
substs: self.monomorphize(&substs),
- variant_index: disr.0 as usize,
+ variant_index: variant_index,
};
let (lldest_i, align) = val.trans_field_ptr(&bcx, field_index);
self.store_operand(&bcx, lldest_i, align.to_align(), op);
}
}
}
+ mir::CastKind::ClosureFnPointer => {
+ match operand.ty.sty {
+ ty::TyClosure(def_id, substs) => {
+ // Get the def_id for FnOnce::call_once
+ let fn_once = bcx.tcx().lang_items.fn_once_trait().unwrap();
+ let call_once = bcx.tcx()
+ .global_tcx().associated_items(fn_once)
+ .find(|it| it.kind == ty::AssociatedKind::Method)
+ .unwrap().def_id;
+ // Now create its substs [Closure, Tuple]
+ let input = bcx.tcx().closure_type(def_id)
+ .subst(bcx.tcx(), substs.substs).input(0);
+ let substs = bcx.tcx().mk_substs([operand.ty, input.skip_binder()]
+ .iter().cloned().map(Kind::from));
+ OperandValue::Immediate(
+ Callee::def(bcx.ccx, call_once, substs)
+ .reify(bcx.ccx))
+ }
+ _ => {
+ bug!("{} cannot be cast to a fn ptr", operand.ty)
+ }
+ }
+ }
mir::CastKind::UnsafeFnPointer => {
// this is a no-op at the LLVM level
operand.val
assert_eq!(dg.ty(), glue::get_drop_glue_type(ccx.shared(), dg.ty()));
let t = dg.ty();
- let sig = tcx.mk_fn_sig(iter::once(tcx.mk_mut_ptr(t)), tcx.mk_nil(), false);
+ let sig = tcx.mk_fn_sig(
+ iter::once(tcx.mk_mut_ptr(t)),
+ tcx.mk_nil(),
+ false,
+ hir::Unsafety::Normal,
+ Abi::Rust
+ );
debug!("predefine_drop_glue: sig={}", sig);
- let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
+ let fn_ty = FnType::new(ccx, sig, &[]);
let llfnty = fn_ty.llvm_type(ccx);
assert!(declare::get_defined_value(ccx, symbol_name).is_none());
output);
}
},
- ty::TyFnDef(.., &ty::BareFnTy{ unsafety, abi, ref sig } ) |
- ty::TyFnPtr(&ty::BareFnTy{ unsafety, abi, ref sig } ) => {
- if unsafety == hir::Unsafety::Unsafe {
+ ty::TyFnDef(.., sig) |
+ ty::TyFnPtr(sig) => {
+ if sig.unsafety() == hir::Unsafety::Unsafe {
output.push_str("unsafe ");
}
+ let abi = sig.abi();
if abi != ::abi::Abi::Rust {
output.push_str("extern \"");
output.push_str(abi.name());
output.push_str("fn(");
- let sig = self.tcx.erase_late_bound_regions_and_normalize(sig);
+ let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig);
if !sig.inputs().is_empty() {
for ¶meter_type in sig.inputs() {
ty::TyStr | ty::TyDynamic(..) => Type::i8(cx),
ty::TyFnDef(..) => Type::nil(cx),
- ty::TyFnPtr(f) => {
- let sig = cx.tcx().erase_late_bound_regions_and_normalize(&f.sig);
- FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
+ ty::TyFnPtr(sig) => {
+ let sig = cx.tcx().erase_late_bound_regions_and_normalize(&sig);
+ FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to()
}
ty::TyTuple(ref tys, _) if tys.is_empty() => Type::nil(cx),
ty::TyTuple(..) => {
//! Conversion from AST representation of types to the ty.rs
//! representation. The main routine here is `ast_ty_to_ty()`: each use
//! is parameterized by an instance of `AstConv`.
-//!
-//! The parameterization of `ast_ty_to_ty()` is because it behaves
-//! somewhat differently during the collect and check phases,
-//! particularly with respect to looking up the types of top-level
-//! items. In the collect phase, the crate context is used as the
-//! `AstConv` instance; in this phase, the `get_item_type()`
-//! function triggers a recursive call to `type_of_item()`
-//! (note that `ast_ty_to_ty()` will detect recursive types and report
-//! an error). In the check phase, when the FnCtxt is used as the
-//! `AstConv`, `get_item_type()` just looks up the item type in
-//! `tcx.types` (using `TyCtxt::item_type`).
use rustc_const_eval::eval_length;
use rustc_data_structures::accumulate_vec::AccumulateVec;
use std::iter;
use syntax::{abi, ast};
use syntax::feature_gate::{GateIssue, emit_feature_err};
-use syntax::symbol::{Symbol, keywords};
+use syntax::symbol::Symbol;
use syntax_pos::Span;
pub trait AstConv<'gcx, 'tcx> {
/// A cache used for the result of `ast_ty_to_ty_cache`
fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>>;
- /// Returns the generic type and lifetime parameters for an item.
- fn get_generics(&self, span: Span, id: DefId)
- -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>;
-
- /// Identify the type for an item, like a type alias, fn, or struct.
- fn get_item_type(&self, span: Span, id: DefId) -> Result<Ty<'tcx>, ErrorReported>;
-
- /// Returns the `TraitDef` for a given trait. This allows you to
- /// figure out the set of type parameters defined on the trait.
- fn get_trait_def(&self, span: Span, id: DefId)
- -> Result<&'tcx ty::TraitDef, ErrorReported>;
-
- /// Ensure that the super-predicates for the trait with the given
- /// id are available and also for the transitive set of
- /// super-predicates.
- fn ensure_super_predicates(&self, span: Span, id: DefId)
- -> Result<(), ErrorReported>;
-
/// Returns the set of bounds in scope for the type parameter with
/// the given id.
- fn get_type_parameter_bounds(&self, span: Span, def_id: ast::NodeId)
- -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>;
+ fn get_type_parameter_bounds(&self, span: Span, def_id: DefId)
+ -> ty::GenericPredicates<'tcx>;
/// Return an (optional) substitution to convert bound type parameters that
/// are in scope into free ones. This function should only return Some
/// Same as ty_infer, but with a known type parameter definition.
fn ty_infer_for_def(&self,
- _def: &ty::TypeParameterDef<'tcx>,
+ _def: &ty::TypeParameterDef,
_substs: &[Kind<'tcx>],
span: Span) -> Ty<'tcx> {
self.ty_infer(span)
&item_segment.parameters,
None);
- assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+ assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
substs
}
// If the type is parameterized by this region, then replace this
// region with the current anon region binding (in other words,
// whatever & would get replaced with).
- let decl_generics = match self.get_generics(span, def_id) {
- Ok(generics) => generics,
- Err(ErrorReported) => {
- // No convenient way to recover from a cycle here. Just bail. Sorry!
- self.tcx().sess.abort_if_errors();
- bug!("ErrorReported returned, but no errors reports?")
- }
- };
+ let decl_generics = tcx.item_generics(def_id);
let expected_num_region_params = decl_generics.regions.len();
let supplied_num_region_params = lifetimes.len();
if expected_num_region_params != supplied_num_region_params {
}
let is_object = self_ty.map_or(false, |ty| ty.sty == TRAIT_OBJECT_DUMMY_SELF);
- let default_needs_object_self = |p: &ty::TypeParameterDef<'tcx>| {
- if let Some(ref default) = p.default {
- if is_object && default.has_self_ty() {
+ let default_needs_object_self = |p: &ty::TypeParameterDef| {
+ if is_object && p.has_default {
+ if ty::queries::ty::get(tcx, span, p.def_id).has_self_ty() {
// There is no suitable inference default for a type parameter
// that references self, in an object type.
return true;
self.ty_infer(span)
};
ty_var
- } else if let Some(default) = def.default {
+ } else if def.has_default {
// No type parameter provided, but a default exists.
// If we are converting an object type, then the
tcx.types.err
} else {
// This is a default type parameter.
- default.subst_spanned(tcx, substs, Some(span))
+ ty::queries::ty::get(tcx, span, def.def_id)
+ .subst_spanned(tcx, substs, Some(span))
}
} else {
// We've already errored above about the mismatch.
trait_def_id,
self_ty,
trait_segment);
- assoc_bindings.first().map(|b| self.tcx().prohibit_projection(b.span));
+ assoc_bindings.first().map(|b| self.prohibit_projection(b.span));
ty::TraitRef::new(trait_def_id, substs)
}
debug!("create_substs_for_ast_trait_ref(trait_segment={:?})",
trait_segment);
- let trait_def = match self.get_trait_def(span, trait_def_id) {
- Ok(trait_def) => trait_def,
- Err(ErrorReported) => {
- // No convenient way to recover from a cycle here. Just bail. Sorry!
- self.tcx().sess.abort_if_errors();
- bug!("ErrorReported returned, but no errors reports?")
- }
- };
+ let trait_def = self.tcx().lookup_trait_def(trait_def_id);
match trait_segment.parameters {
hir::AngleBracketedParameters(_) => {
// Otherwise, we have to walk through the supertraits to find
// those that do.
- self.ensure_super_predicates(binding.span, trait_ref.def_id())?;
-
let candidates =
traits::supertraits(tcx, trait_ref.clone())
.filter(|r| self.trait_defines_associated_type_named(r.def_id(), binding.item_name));
item_segment: &hir::PathSegment)
-> Ty<'tcx>
{
- let tcx = self.tcx();
- let decl_ty = match self.get_item_type(span, did) {
- Ok(ty) => ty,
- Err(ErrorReported) => {
- return tcx.types.err;
- }
- };
-
let substs = self.ast_path_substs_for_ty(span, did, item_segment);
- decl_ty.subst(self.tcx(), substs)
+ ty::queries::ty::get(self.tcx(), span, did).subst(self.tcx(), substs)
}
/// Transform a PolyTraitRef into a PolyExistentialTraitRef by
})
});
- // ensure the super predicates and stop if we encountered an error
- if self.ensure_super_predicates(span, principal.def_id()).is_err() {
- return tcx.types.err;
- }
-
// check that there are no gross object safety violations,
// most importantly, that the supertraits don't contain Self,
// to avoid ICE-s.
}
// Search for a bound on a type parameter which includes the associated item
- // given by assoc_name. ty_param_node_id is the node id for the type parameter
- // (which might be `Self`, but only if it is the `Self` of a trait, not an
- // impl). This function will fail if there are no suitable bounds or there is
+ // given by `assoc_name`. `ty_param_def_id` is the `DefId` for the type parameter
+ // This function will fail if there are no suitable bounds or there is
// any ambiguity.
fn find_bound_for_assoc_item(&self,
- ty_param_node_id: ast::NodeId,
- ty_param_name: ast::Name,
+ ty_param_def_id: DefId,
assoc_name: ast::Name,
span: Span)
-> Result<ty::PolyTraitRef<'tcx>, ErrorReported>
{
let tcx = self.tcx();
- let bounds = match self.get_type_parameter_bounds(span, ty_param_node_id) {
- Ok(v) => v,
- Err(ErrorReported) => {
- return Err(ErrorReported);
- }
- };
-
- // Ensure the super predicates and stop if we encountered an error.
- if bounds.iter().any(|b| self.ensure_super_predicates(span, b.def_id()).is_err()) {
- return Err(ErrorReported);
- }
+ let bounds: Vec<_> = self.get_type_parameter_bounds(span, ty_param_def_id)
+ .predicates.into_iter().filter_map(|p| p.to_opt_poly_trait_ref()).collect();
// Check that there is exactly one way to find an associated type with the
// correct name.
traits::transitive_bounds(tcx, &bounds)
.filter(|b| self.trait_defines_associated_type_named(b.def_id(), assoc_name));
+ let param_node_id = tcx.hir.as_local_node_id(ty_param_def_id).unwrap();
+ let param_name = tcx.hir.ty_param_name(param_node_id);
self.one_bound_for_assoc_type(suitable_bounds,
- &ty_param_name.as_str(),
+ ¶m_name.as_str(),
&assoc_name.as_str(),
span)
}
debug!("associated_path_def_to_ty: {:?}::{}", ty, assoc_name);
- tcx.prohibit_type_params(slice::ref_slice(item_segment));
+ self.prohibit_type_params(slice::ref_slice(item_segment));
// Find the type of the associated item, and the trait where the associated
// item is declared.
(_, Def::SelfTy(Some(_), Some(impl_def_id))) => {
// `Self` in an impl of a trait - we have a concrete self type and a
// trait reference.
- // FIXME: Self type is not always computed when we are here because type parameter
- // bounds may affect Self type and have to be converted before it.
- let trait_ref = if impl_def_id.is_local() {
- tcx.impl_trait_refs.borrow().get(&impl_def_id).cloned().and_then(|x| x)
- } else {
- tcx.impl_trait_ref(impl_def_id)
- };
- let trait_ref = if let Some(trait_ref) = trait_ref {
- trait_ref
- } else {
- tcx.sess.span_err(span, "`Self` type is used before it's determined");
- return (tcx.types.err, Def::Err);
+ let trait_ref = match tcx.impl_trait_ref(impl_def_id) {
+ Some(trait_ref) => trait_ref,
+ None => {
+ // A cycle error occurred, most likely.
+ return (tcx.types.err, Def::Err);
+ }
};
+
let trait_ref = if let Some(free_substs) = self.get_free_substs() {
trait_ref.subst(tcx, free_substs)
} else {
trait_ref
};
- if self.ensure_super_predicates(span, trait_ref.def_id).is_err() {
- return (tcx.types.err, Def::Err);
- }
-
let candidates =
traits::supertraits(tcx, ty::Binder(trait_ref))
.filter(|r| self.trait_defines_associated_type_named(r.def_id(),
Err(ErrorReported) => return (tcx.types.err, Def::Err),
}
}
- (&ty::TyParam(_), Def::SelfTy(Some(trait_did), None)) => {
- let trait_node_id = tcx.hir.as_local_node_id(trait_did).unwrap();
- match self.find_bound_for_assoc_item(trait_node_id,
- keywords::SelfType.name(),
- assoc_name,
- span) {
- Ok(bound) => bound,
- Err(ErrorReported) => return (tcx.types.err, Def::Err),
- }
- }
+ (&ty::TyParam(_), Def::SelfTy(Some(param_did), None)) |
(&ty::TyParam(_), Def::TyParam(param_did)) => {
- let param_node_id = tcx.hir.as_local_node_id(param_did).unwrap();
- let param_name = tcx.type_parameter_def(param_node_id).name;
- match self.find_bound_for_assoc_item(param_node_id,
- param_name,
- assoc_name,
- span) {
+ match self.find_bound_for_assoc_item(param_did, assoc_name, span) {
Ok(bound) => bound,
Err(ErrorReported) => return (tcx.types.err, Def::Err),
}
{
let tcx = self.tcx();
- tcx.prohibit_type_params(slice::ref_slice(item_segment));
+ self.prohibit_type_params(slice::ref_slice(item_segment));
let self_ty = if let Some(ty) = opt_self_ty {
ty
self.projected_ty(span, trait_ref, item_segment.name)
}
+ pub fn prohibit_type_params(&self, segments: &[hir::PathSegment]) {
+ for segment in segments {
+ for typ in segment.parameters.types() {
+ struct_span_err!(self.tcx().sess, typ.span, E0109,
+ "type parameters are not allowed on this type")
+ .span_label(typ.span, &format!("type parameter not allowed"))
+ .emit();
+ break;
+ }
+ for lifetime in segment.parameters.lifetimes() {
+ struct_span_err!(self.tcx().sess, lifetime.span, E0110,
+ "lifetime parameters are not allowed on this type")
+ .span_label(lifetime.span,
+ &format!("lifetime parameter not allowed on this type"))
+ .emit();
+ break;
+ }
+ for binding in segment.parameters.bindings() {
+ self.prohibit_projection(binding.span);
+ break;
+ }
+ }
+ }
+
+ pub fn prohibit_projection(&self, span: Span) {
+ let mut err = struct_span_err!(self.tcx().sess, span, E0229,
+ "associated type bindings are not allowed here");
+ err.span_label(span, &format!("associate type not allowed here")).emit();
+ }
+
// Check a type Path and convert it to a Ty.
pub fn def_to_ty(&self,
opt_self_ty: Option<Ty<'tcx>>,
match path.def {
Def::Enum(did) | Def::TyAlias(did) | Def::Struct(did) | Def::Union(did) => {
assert_eq!(opt_self_ty, None);
- tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
+ self.prohibit_type_params(path.segments.split_last().unwrap().1);
self.ast_path_to_ty(span, did, path.segments.last().unwrap())
}
Def::Variant(did) if permit_variants => {
// Convert "variant type" as if it were a real type.
// The resulting `Ty` is type of the variant's enum for now.
assert_eq!(opt_self_ty, None);
- tcx.prohibit_type_params(path.segments.split_last().unwrap().1);
+ self.prohibit_type_params(path.segments.split_last().unwrap().1);
self.ast_path_to_ty(span,
tcx.parent_def_id(did).unwrap(),
path.segments.last().unwrap())
}
Def::TyParam(did) => {
assert_eq!(opt_self_ty, None);
- tcx.prohibit_type_params(&path.segments);
+ self.prohibit_type_params(&path.segments);
let node_id = tcx.hir.as_local_node_id(did).unwrap();
- let param = tcx.ty_param_defs.borrow().get(&node_id)
- .map(ty::ParamTy::for_def);
- if let Some(p) = param {
- p.to_ty(tcx)
- } else {
- // Only while computing defaults of earlier type
- // parameters can a type parameter be missing its def.
- struct_span_err!(tcx.sess, span, E0128,
- "type parameters with a default cannot use \
- forward declared identifiers")
- .span_label(span, &format!("defaulted type parameters \
- cannot be forward declared"))
- .emit();
- tcx.types.err
- }
+ let item_id = tcx.hir.get_parent_node(node_id);
+ let item_def_id = tcx.hir.local_def_id(item_id);
+ let generics = tcx.item_generics(item_def_id);
+ let index = generics.type_param_to_index[&tcx.hir.local_def_id(node_id).index];
+ tcx.mk_param(index, tcx.hir.name(node_id))
}
Def::SelfTy(_, Some(def_id)) => {
// Self in impl (we know the concrete type).
assert_eq!(opt_self_ty, None);
- tcx.prohibit_type_params(&path.segments);
+ self.prohibit_type_params(&path.segments);
- // FIXME: Self type is not always computed when we are here because type parameter
- // bounds may affect Self type and have to be converted before it.
- let ty = if def_id.is_local() {
- tcx.item_types.borrow().get(&def_id).cloned()
+ let ty = ty::queries::ty::get(tcx, span, def_id);
+ if let Some(free_substs) = self.get_free_substs() {
+ ty.subst(tcx, free_substs)
} else {
- Some(tcx.item_type(def_id))
- };
- if let Some(ty) = ty {
- if let Some(free_substs) = self.get_free_substs() {
- ty.subst(tcx, free_substs)
- } else {
- ty
- }
- } else {
- tcx.sess.span_err(span, "`Self` type is used before it's determined");
- tcx.types.err
+ ty
}
}
Def::SelfTy(Some(_), None) => {
// Self in trait.
assert_eq!(opt_self_ty, None);
- tcx.prohibit_type_params(&path.segments);
+ self.prohibit_type_params(&path.segments);
tcx.mk_self_type()
}
Def::AssociatedTy(def_id) => {
- tcx.prohibit_type_params(&path.segments[..path.segments.len()-2]);
+ self.prohibit_type_params(&path.segments[..path.segments.len()-2]);
let trait_did = tcx.parent_def_id(def_id).unwrap();
self.qpath_to_ty(span,
opt_self_ty,
}
Def::PrimTy(prim_ty) => {
assert_eq!(opt_self_ty, None);
- tcx.prim_ty_to_ty(&path.segments, prim_ty)
+ self.prohibit_type_params(&path.segments);
+ match prim_ty {
+ hir::TyBool => tcx.types.bool,
+ hir::TyChar => tcx.types.char,
+ hir::TyInt(it) => tcx.mk_mach_int(it),
+ hir::TyUint(uit) => tcx.mk_mach_uint(uit),
+ hir::TyFloat(ft) => tcx.mk_mach_float(ft),
+ hir::TyStr => tcx.mk_str()
+ }
}
Def::Err => {
self.set_tainted_by_errors();
// warning then. (Once we fix #32330, the regions we are
// checking for here would be considered early bound
// anyway.)
- let inputs = bare_fn_ty.sig.inputs();
+ let inputs = bare_fn_ty.inputs();
let late_bound_in_args = tcx.collect_constrained_late_bound_regions(
&inputs.map_bound(|i| i.to_owned()));
- let output = bare_fn_ty.sig.output();
+ let output = bare_fn_ty.output();
let late_bound_in_ret = tcx.collect_referenced_late_bound_regions(&output);
for br in late_bound_in_ret.difference(&late_bound_in_args) {
let br_name = match *br {
hir::TyTraitObject(ref bounds, ref lifetime) => {
self.conv_object_ty_poly_trait_ref(ast_ty.span, bounds, lifetime)
}
- hir::TyImplTrait(ref bounds) => {
- use collect::{compute_bounds, SizedByDefault};
-
+ hir::TyImplTrait(_) => {
// Figure out if we can allow an `impl Trait` here, by walking up
// to a `fn` or inherent `impl` method, going only through `Ty`
// or `TraitRef` nodes (as nothing else should be in types) and
// Create the anonymized type.
if allow {
let def_id = tcx.hir.local_def_id(ast_ty.id);
- if let Err(ErrorReported) = self.get_generics(ast_ty.span, def_id) {
- return tcx.types.err;
- }
- let substs = Substs::identity_for_item(tcx, def_id);
- let ty = tcx.mk_anon(tcx.hir.local_def_id(ast_ty.id), substs);
-
- // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
- let bounds = compute_bounds(self, ty, bounds,
- SizedByDefault::Yes,
- ast_ty.span);
- let predicates = bounds.predicates(tcx, ty);
- let predicates = tcx.lift_to_global(&predicates).unwrap();
- tcx.predicates.borrow_mut().insert(def_id, ty::GenericPredicates {
- parent: None,
- predicates: predicates
- });
-
- ty
+ tcx.mk_anon(def_id, Substs::identity_for_item(tcx, def_id))
} else {
span_err!(tcx.sess, ast_ty.span, E0562,
"`impl Trait` not allowed outside of function \
unsafety: hir::Unsafety,
abi: abi::Abi,
decl: &hir::FnDecl)
- -> &'tcx ty::BareFnTy<'tcx> {
+ -> ty::PolyFnSig<'tcx> {
debug!("ty_of_fn");
let input_tys: Vec<Ty> =
debug!("ty_of_fn: output_ty={:?}", output_ty);
- self.tcx().mk_bare_fn(ty::BareFnTy {
- unsafety: unsafety,
- abi: abi,
- sig: ty::Binder(self.tcx().mk_fn_sig(
- input_tys.into_iter(),
- output_ty,
- decl.variadic
- )),
- })
+ ty::Binder(self.tcx().mk_fn_sig(
+ input_tys.into_iter(),
+ output_ty,
+ decl.variadic,
+ unsafety,
+ abi
+ ))
}
pub fn ty_of_closure(&self,
decl: &hir::FnDecl,
abi: abi::Abi,
expected_sig: Option<ty::FnSig<'tcx>>)
- -> ty::ClosureTy<'tcx>
+ -> ty::PolyFnSig<'tcx>
{
debug!("ty_of_closure(expected_sig={:?})",
expected_sig);
debug!("ty_of_closure: output_ty={:?}", output_ty);
- ty::ClosureTy {
- unsafety: unsafety,
- abi: abi,
- sig: ty::Binder(self.tcx().mk_fn_sig(input_tys, output_ty, decl.variadic)),
- }
+ ty::Binder(self.tcx().mk_fn_sig(
+ input_tys,
+ output_ty,
+ decl.variadic,
+ unsafety,
+ abi
+ ))
}
/// Given the bounds on an object, determines what single region bound (if any) we can
debug!("compute_opt_region_bound(existential_predicates={:?})",
existential_predicates);
- if let Some(principal) = existential_predicates.principal() {
- if let Err(ErrorReported) = self.ensure_super_predicates(span, principal.def_id()) {
- return Some(tcx.mk_region(ty::ReStatic));
- }
- }
-
// No explicit region bound specified. Therefore, examine trait
// bounds and see if we can derive region bounds from those.
let derived_region_bounds =
fn check_type_argument_count(tcx: TyCtxt, span: Span, supplied: usize,
ty_param_defs: &[ty::TypeParameterDef]) {
let accepted = ty_param_defs.len();
- let required = ty_param_defs.iter().take_while(|x| x.default.is_none()) .count();
+ let required = ty_param_defs.iter().take_while(|x| !x.has_default).count();
if supplied < required {
let expected = if required < accepted {
"expected at least"
use super::{DeferredCallResolution, Expectation, FnCtxt, TupleArgumentsFlag};
-use CrateCtxt;
use hir::def::Def;
use hir::def_id::{DefId, LOCAL_CRATE};
use rustc::{infer, traits};
-use rustc::ty::{self, LvaluePreference, Ty};
+use rustc::ty::{self, TyCtxt, LvaluePreference, Ty};
+use rustc::ty::subst::Subst;
+use syntax::abi;
use syntax::symbol::Symbol;
use syntax_pos::Span;
/// Check that it is legal to call methods of the trait corresponding
/// to `trait_id` (this only cares about the trait, not the specific
/// method that is called)
-pub fn check_legal_trait_for_method_call(ccx: &CrateCtxt, span: Span, trait_id: DefId) {
- if ccx.tcx.lang_items.drop_trait() == Some(trait_id) {
- struct_span_err!(ccx.tcx.sess,
- span,
- E0040,
- "explicit use of destructor method")
+pub fn check_legal_trait_for_method_call(tcx: TyCtxt, span: Span, trait_id: DefId) {
+ if tcx.lang_items.drop_trait() == Some(trait_id) {
+ struct_span_err!(tcx.sess, span, E0040, "explicit use of destructor method")
.span_label(span, &format!("explicit destructor calls not allowed"))
.emit();
}
// haven't yet decided on whether the closure is fn vs
// fnmut vs fnonce. If so, we have to defer further processing.
if self.closure_kind(def_id).is_none() {
- let closure_ty = self.closure_type(def_id, substs);
+ let closure_ty = self.closure_type(def_id).subst(self.tcx, substs.substs);
let fn_sig = self.replace_late_bound_regions_with_fresh_var(call_expr.span,
infer::FnCall,
- &closure_ty.sig)
+ &closure_ty)
.0;
self.record_deferred_call_resolution(def_id,
Box::new(CallResolution {
arg_exprs: &'gcx [hir::Expr],
expected: Expectation<'tcx>)
-> Ty<'tcx> {
- let error_fn_sig;
-
let (fn_sig, def_span) = match callee_ty.sty {
- ty::TyFnDef(def_id, .., &ty::BareFnTy {ref sig, ..}) => {
+ ty::TyFnDef(def_id, .., sig) => {
(sig, self.tcx.hir.span_if_local(def_id))
}
- ty::TyFnPtr(&ty::BareFnTy {ref sig, ..}) => (sig, None),
+ ty::TyFnPtr(sig) => (sig, None),
ref t => {
let mut unit_variant = None;
if let &ty::TyAdt(adt_def, ..) = t {
// This is the "default" function signature, used in case of error.
// In that case, we check each argument against "error" in order to
// set up all the node type bindings.
- error_fn_sig = ty::Binder(self.tcx.mk_fn_sig(
+ (ty::Binder(self.tcx.mk_fn_sig(
self.err_args(arg_exprs.len()).into_iter(),
self.tcx.types.err,
false,
- ));
-
- (&error_fn_sig, None)
+ hir::Unsafety::Normal,
+ abi::Abi::Rust
+ )), None)
}
};
// previously appeared within a `Binder<>` and hence would not
// have been normalized before.
let fn_sig =
- self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, fn_sig)
+ self.replace_late_bound_regions_with_fresh_var(call_expr.span, infer::FnCall, &fn_sig)
.0;
let fn_sig = self.normalize_associated_types_in(call_expr.span, &fn_sig);
// (This always bites me, should find a way to
// refactor it.)
let method_sig = fcx.tcx
- .no_late_bound_regions(method_callee.ty.fn_sig())
+ .no_late_bound_regions(&method_callee.ty.fn_sig())
.unwrap();
debug!("attempt_resolution: method_callee={:?}", method_callee);
expected_sig);
let expr_def_id = self.tcx.hir.local_def_id(expr.id);
- let mut fn_ty = AstConv::ty_of_closure(self,
- hir::Unsafety::Normal,
- decl,
- Abi::RustCall,
- expected_sig);
+ let sig = AstConv::ty_of_closure(self,
+ hir::Unsafety::Normal,
+ decl,
+ Abi::RustCall,
+ expected_sig);
// Create type variables (for now) to represent the transformed
// types of upvars. These will be unified during the upvar
debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
let extent = self.tcx.region_maps.call_site_extent(expr.id, body.value.id);
- let fn_sig = self.tcx.liberate_late_bound_regions(extent, &fn_ty.sig);
+ let fn_sig = self.tcx.liberate_late_bound_regions(extent, &sig);
let fn_sig = self.inh.normalize_associated_types_in(body.value.span,
body.value.id, &fn_sig);
- check_fn(self,
- hir::Unsafety::Normal,
- expr.id,
- &fn_sig,
- decl,
- expr.id,
- body);
+ check_fn(self, fn_sig, decl, expr.id, body);
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.
- fn_ty.sig.0 = self.tcx.mk_fn_sig(
- iter::once(self.tcx.intern_tup(fn_ty.sig.skip_binder().inputs(), false)),
- fn_ty.sig.skip_binder().output(),
- fn_ty.sig.variadic()
- );
+ let sig = sig.map_bound(|sig| self.tcx.mk_fn_sig(
+ iter::once(self.tcx.intern_tup(sig.inputs(), false)),
+ sig.output(),
+ sig.variadic,
+ sig.unsafety,
+ sig.abi
+ ));
debug!("closure for {:?} --> sig={:?} opt_kind={:?}",
expr_def_id,
- fn_ty.sig,
+ sig,
opt_kind);
- self.tables.borrow_mut().closure_tys.insert(expr.id, fn_ty);
+ self.tables.borrow_mut().closure_tys.insert(expr.id, sig);
match opt_kind {
Some(kind) => {
self.tables.borrow_mut().closure_kinds.insert(expr.id, kind);
let ret_param_ty = self.resolve_type_vars_if_possible(&ret_param_ty);
debug!("deduce_sig_from_projection: ret_param_ty {:?}", ret_param_ty);
- let fn_sig = self.tcx.mk_fn_sig(input_tys.cloned(), ret_param_ty, false);
+ let fn_sig = self.tcx.mk_fn_sig(
+ input_tys.cloned(),
+ ret_param_ty,
+ false,
+ hir::Unsafety::Normal,
+ Abi::Rust
+ );
debug!("deduce_sig_from_projection: fn_sig {:?}", fn_sig);
Some(fn_sig)
use check::FnCtxt;
use rustc::hir;
+use rustc::hir::def_id::DefId;
use rustc::infer::{Coercion, InferOk, TypeTrace};
use rustc::traits::{self, ObligationCause, ObligationCauseCode};
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow};
-use rustc::ty::{self, LvaluePreference, TypeAndMut, Ty};
+use rustc::ty::{self, LvaluePreference, TypeAndMut,
+ Ty, ClosureSubsts};
use rustc::ty::fold::TypeFoldable;
use rustc::ty::error::TypeError;
use rustc::ty::relate::RelateResult;
+use rustc::ty::subst::Subst;
+use syntax::abi;
+use syntax::feature_gate;
use util::common::indent;
use std::cell::RefCell;
// unsafe qualifier.
self.coerce_from_fn_pointer(a, a_f, b)
}
+ ty::TyClosure(def_id_a, substs_a) => {
+ // Non-capturing closures are coercible to
+ // function pointers
+ self.coerce_closure_to_fn(a, def_id_a, substs_a, b)
+ }
_ => {
// Otherwise, just use unification rules.
self.unify_and_identity(a, b)
fn coerce_from_safe_fn(&self,
a: Ty<'tcx>,
- fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+ fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
if let ty::TyFnPtr(fn_ty_b) = b.sty {
- match (fn_ty_a.unsafety, fn_ty_b.unsafety) {
+ match (fn_ty_a.unsafety(), fn_ty_b.unsafety()) {
(hir::Unsafety::Normal, hir::Unsafety::Unsafe) => {
let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
return self.unify_and_identity(unsafe_a, b)
fn coerce_from_fn_pointer(&self,
a: Ty<'tcx>,
- fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+ fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
//! Attempts to coerce from the type of a Rust function item
fn coerce_from_fn_item(&self,
a: Ty<'tcx>,
- fn_ty_a: &'tcx ty::BareFnTy<'tcx>,
+ fn_ty_a: ty::PolyFnSig<'tcx>,
b: Ty<'tcx>)
-> CoerceResult<'tcx> {
//! Attempts to coerce from the type of a Rust function item
}
}
+ fn coerce_closure_to_fn(&self,
+ a: Ty<'tcx>,
+ def_id_a: DefId,
+ substs_a: ClosureSubsts<'tcx>,
+ b: Ty<'tcx>)
+ -> CoerceResult<'tcx> {
+ //! Attempts to coerce from the type of a non-capturing closure
+ //! into a function pointer.
+ //!
+
+ let b = self.shallow_resolve(b);
+
+ let node_id_a = self.tcx.hir.as_local_node_id(def_id_a).unwrap();
+ match b.sty {
+ ty::TyFnPtr(_) if self.tcx.with_freevars(node_id_a, |v| v.is_empty()) => {
+ if !self.tcx.sess.features.borrow().closure_to_fn_coercion {
+ feature_gate::emit_feature_err(&self.tcx.sess.parse_sess,
+ "closure_to_fn_coercion",
+ self.cause.span,
+ feature_gate::GateIssue::Language,
+ feature_gate::CLOSURE_TO_FN_COERCION);
+ return self.unify_and_identity(a, b);
+ }
+ // We coerce the closure, which has fn type
+ // `extern "rust-call" fn((arg0,arg1,...)) -> _`
+ // to
+ // `fn(arg0,arg1,...) -> _`
+ let sig = self.closure_type(def_id_a).subst(self.tcx, substs_a.substs);
+ let converted_sig = sig.map_bound(|s| {
+ let params_iter = match s.inputs()[0].sty {
+ ty::TyTuple(params, _) => {
+ params.into_iter().cloned()
+ }
+ _ => bug!(),
+ };
+ self.tcx.mk_fn_sig(
+ params_iter,
+ s.output(),
+ s.variadic,
+ hir::Unsafety::Normal,
+ abi::Abi::Rust
+ )
+ });
+ let pointer_ty = self.tcx.mk_fn_ptr(converted_sig);
+ debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})",
+ a, b, pointer_ty);
+ self.unify_and_identity(pointer_ty, b)
+ .map(|(ty, _)| (ty, Adjust::ClosureFnPointer))
+ }
+ _ => self.unify_and_identity(a, b),
+ }
+ }
+
fn coerce_unsafe_ptr(&self,
a: Ty<'tcx>,
b: Ty<'tcx>,
use rustc::hir::{self, ImplItemKind, TraitItemKind};
use rustc::infer::{self, InferOk};
use rustc::middle::free_region::FreeRegionMap;
-use rustc::ty;
+use rustc::ty::{self, TyCtxt};
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::error::{ExpectedFound, TypeError};
use rustc::ty::subst::{Subst, Substs};
use syntax::ast;
use syntax_pos::Span;
-use CrateCtxt;
use super::assoc;
use super::{Inherited, FnCtxt};
use astconv::ExplicitSelf;
/// - trait_m: the method in the trait
/// - impl_trait_ref: the TraitRef corresponding to the trait implementation
-pub fn compare_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+pub fn compare_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_m: &ty::AssociatedItem,
impl_m_span: Span,
impl_m_body_id: ast::NodeId,
debug!("compare_impl_method(impl_trait_ref={:?})",
impl_trait_ref);
- if let Err(ErrorReported) = compare_self_type(ccx,
+ if let Err(ErrorReported) = compare_self_type(tcx,
impl_m,
impl_m_span,
trait_m,
return;
}
- if let Err(ErrorReported) = compare_number_of_generics(ccx,
+ if let Err(ErrorReported) = compare_number_of_generics(tcx,
impl_m,
impl_m_span,
trait_m,
return;
}
- if let Err(ErrorReported) = compare_number_of_method_arguments(ccx,
+ if let Err(ErrorReported) = compare_number_of_method_arguments(tcx,
impl_m,
impl_m_span,
trait_m,
return;
}
- if let Err(ErrorReported) = compare_predicate_entailment(ccx,
+ if let Err(ErrorReported) = compare_predicate_entailment(tcx,
impl_m,
impl_m_span,
impl_m_body_id,
}
}
-fn compare_predicate_entailment<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_predicate_entailment<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_m: &ty::AssociatedItem,
impl_m_span: Span,
impl_m_body_id: ast::NodeId,
impl_trait_ref: ty::TraitRef<'tcx>,
old_broken_mode: bool)
-> Result<(), ErrorReported> {
- let tcx = ccx.tcx;
-
let trait_to_impl_substs = impl_trait_ref.substs;
let cause = ObligationCause {
let trait_m_predicates = tcx.item_predicates(trait_m.def_id);
// Check region bounds.
- check_region_bounds_on_impl_method(ccx,
+ check_region_bounds_on_impl_method(tcx,
impl_m_span,
impl_m,
&trait_m_generics,
trait_param_env,
normalize_cause.clone());
- tcx.infer_ctxt(trait_param_env, Reveal::NotSpecializable).enter(|infcx| {
- let inh = Inherited::new(ccx, infcx);
+ tcx.infer_ctxt(trait_param_env, Reveal::UserFacing).enter(|infcx| {
+ let inh = Inherited::new(infcx);
let infcx = &inh.infcx;
let fulfillment_cx = &inh.fulfillment_cx;
// Compute skolemized form of impl and trait method tys.
let tcx = infcx.tcx;
- let m_fty = |method: &ty::AssociatedItem| {
+ let m_sig = |method: &ty::AssociatedItem| {
match tcx.item_type(method.def_id).sty {
ty::TyFnDef(_, _, f) => f,
_ => bug!()
}
};
- let impl_m_fty = m_fty(impl_m);
- let trait_m_fty = m_fty(trait_m);
let (impl_sig, _) =
infcx.replace_late_bound_regions_with_fresh_var(impl_m_span,
infer::HigherRankedType,
- &impl_m_fty.sig);
+ &m_sig(impl_m));
let impl_sig =
impl_sig.subst(tcx, impl_to_skol_substs);
let impl_sig =
impl_m_span,
impl_m_body_id,
&impl_sig);
- let impl_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: impl_m_fty.unsafety,
- abi: impl_m_fty.abi,
- sig: ty::Binder(impl_sig.clone()),
- }));
+ let impl_fty = tcx.mk_fn_ptr(ty::Binder(impl_sig));
debug!("compare_impl_method: impl_fty={:?}", impl_fty);
let trait_sig = tcx.liberate_late_bound_regions(
infcx.parameter_environment.free_id_outlive,
- &trait_m_fty.sig);
+ &m_sig(trait_m));
let trait_sig =
trait_sig.subst(tcx, trait_to_skol_substs);
let trait_sig =
impl_m_span,
impl_m_body_id,
&trait_sig);
- let trait_fty = tcx.mk_fn_ptr(tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: trait_m_fty.unsafety,
- abi: trait_m_fty.abi,
- sig: ty::Binder(trait_sig.clone()),
- }));
+ let trait_fty = tcx.mk_fn_ptr(ty::Binder(trait_sig));
debug!("compare_impl_method: trait_fty={:?}", trait_fty);
})
}
-fn check_region_bounds_on_impl_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn check_region_bounds_on_impl_method<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
span: Span,
impl_m: &ty::AssociatedItem,
- trait_generics: &ty::Generics<'tcx>,
- impl_generics: &ty::Generics<'tcx>,
+ trait_generics: &ty::Generics,
+ impl_generics: &ty::Generics,
trait_to_skol_substs: &Substs<'tcx>,
impl_to_skol_substs: &Substs<'tcx>)
-> Result<(), ErrorReported> {
// are zero. Since I don't quite know how to phrase things at
// the moment, give a kind of vague error message.
if trait_params.len() != impl_params.len() {
- struct_span_err!(ccx.tcx.sess,
+ struct_span_err!(tcx.sess,
span,
E0195,
"lifetime parameters or bounds on method `{}` do not match the \
}
}
-fn compare_self_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_self_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_m: &ty::AssociatedItem,
impl_m_span: Span,
trait_m: &ty::AssociatedItem,
impl_trait_ref: ty::TraitRef<'tcx>)
-> Result<(), ErrorReported>
{
- let tcx = ccx.tcx;
// Try to give more informative error messages about self typing
// mismatches. Note that any mismatch will also be detected
// below, where we construct a canonical function type that
Ok(())
}
-fn compare_number_of_generics<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_number_of_generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_m: &ty::AssociatedItem,
impl_m_span: Span,
trait_m: &ty::AssociatedItem,
trait_item_span: Option<Span>)
-> Result<(), ErrorReported> {
- let tcx = ccx.tcx;
let impl_m_generics = tcx.item_generics(impl_m.def_id);
let trait_m_generics = tcx.item_generics(trait_m.def_id);
let num_impl_m_type_params = impl_m_generics.types.len();
Ok(())
}
-fn compare_number_of_method_arguments<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn compare_number_of_method_arguments<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_m: &ty::AssociatedItem,
impl_m_span: Span,
trait_m: &ty::AssociatedItem,
trait_item_span: Option<Span>)
-> Result<(), ErrorReported> {
- let tcx = ccx.tcx;
let m_fty = |method: &ty::AssociatedItem| {
match tcx.item_type(method.def_id).sty {
ty::TyFnDef(_, _, f) => f,
};
let impl_m_fty = m_fty(impl_m);
let trait_m_fty = m_fty(trait_m);
- let trait_number_args = trait_m_fty.sig.inputs().skip_binder().len();
- let impl_number_args = impl_m_fty.sig.inputs().skip_binder().len();
+ let trait_number_args = trait_m_fty.inputs().skip_binder().len();
+ let impl_number_args = impl_m_fty.inputs().skip_binder().len();
if trait_number_args != impl_number_args {
let trait_m_node_id = tcx.hir.as_local_node_id(trait_m.def_id);
let trait_span = if let Some(trait_id) = trait_m_node_id {
Ok(())
}
-pub fn compare_const_impl<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+pub fn compare_const_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_c: &ty::AssociatedItem,
impl_c_span: Span,
trait_c: &ty::AssociatedItem,
impl_trait_ref: ty::TraitRef<'tcx>) {
debug!("compare_const_impl(impl_trait_ref={:?})", impl_trait_ref);
- let tcx = ccx.tcx;
- tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
let mut fulfillment_cx = traits::FulfillmentContext::new();
// The below is for the most part highly similar to the procedure
match method.def() {
Def::Method(def_id) => {
match self.tcx.item_type(def_id).sty {
- ty::TypeVariants::TyFnDef(_, _, fty) => {
- fty.sig.skip_binder().inputs().len() == 1
+ ty::TypeVariants::TyFnDef(_, _, sig) => {
+ sig.inputs().skip_binder().len() == 1
}
_ => false,
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use CrateCtxt;
use check::regionck::RegionCtxt;
use hir::def_id::DefId;
/// struct/enum definition for the nominal type itself (i.e.
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
///
-pub fn check_drop_impl(ccx: &CrateCtxt, drop_impl_did: DefId) -> Result<(), ()> {
- let dtor_self_type = ccx.tcx.item_type(drop_impl_did);
- let dtor_predicates = ccx.tcx.item_predicates(drop_impl_did);
+pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ drop_impl_did: DefId) -> Result<(), ()> {
+ let dtor_self_type = tcx.item_type(drop_impl_did);
+ let dtor_predicates = tcx.item_predicates(drop_impl_did);
match dtor_self_type.sty {
ty::TyAdt(adt_def, self_to_impl_substs) => {
- ensure_drop_params_and_item_params_correspond(ccx,
+ ensure_drop_params_and_item_params_correspond(tcx,
drop_impl_did,
dtor_self_type,
adt_def.did)?;
- ensure_drop_predicates_are_implied_by_item_defn(ccx,
+ ensure_drop_predicates_are_implied_by_item_defn(tcx,
drop_impl_did,
&dtor_predicates,
adt_def.did,
_ => {
// Destructors only work on nominal types. This was
// already checked by coherence, so we can panic here.
- let span = ccx.tcx.def_span(drop_impl_did);
+ let span = tcx.def_span(drop_impl_did);
span_bug!(span,
"should have been rejected by coherence check: {}",
dtor_self_type);
}
fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
- ccx: &CrateCtxt<'a, 'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
drop_impl_did: DefId,
drop_impl_ty: Ty<'tcx>,
self_type_did: DefId)
-> Result<(), ()>
{
- let tcx = ccx.tcx;
let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
// check that the impl type can be made to match the trait type.
let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id);
- tcx.infer_ctxt(impl_param_env, Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt(impl_param_env, Reveal::UserFacing).enter(|infcx| {
let tcx = infcx.tcx;
let mut fulfillment_cx = traits::FulfillmentContext::new();
/// Confirms that every predicate imposed by dtor_predicates is
/// implied by assuming the predicates attached to self_type_did.
fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
- ccx: &CrateCtxt<'a, 'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
drop_impl_did: DefId,
dtor_predicates: &ty::GenericPredicates<'tcx>,
self_type_did: DefId,
// absent. So we report an error that the Drop impl injected a
// predicate that is not present on the struct definition.
- let tcx = ccx.tcx;
-
let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
let drop_impl_span = tcx.def_span(drop_impl_did);
// Find the `impl<..> Drop for _` to inspect any
// attributes attached to the impl's generics.
- let dtor_method = adt_def.destructor()
+ let dtor_method = adt_def.destructor(tcx)
.expect("dtorck type without destructor impossible");
let method = tcx.associated_item(dtor_method);
let impl_def_id = method.container.id();
use intrinsics;
use rustc::traits::{ObligationCause, ObligationCauseCode};
use rustc::ty::subst::Substs;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, TyCtxt, Ty};
use rustc::util::nodemap::FxHashMap;
-use {CrateCtxt, require_same_types};
+use require_same_types;
use syntax::abi::Abi;
use syntax::ast;
use std::iter;
-fn equate_intrinsic_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn equate_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
it: &hir::ForeignItem,
n_tps: usize,
abi: Abi,
inputs: Vec<Ty<'tcx>>,
output: Ty<'tcx>) {
- let tcx = ccx.tcx;
let def_id = tcx.hir.local_def_id(it.id);
let substs = Substs::for_item(tcx, def_id,
|_, _| tcx.mk_region(ty::ReErased),
|def, _| tcx.mk_param_from_def(def));
- let fty = tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Unsafe,
- abi: abi,
- sig: ty::Binder(tcx.mk_fn_sig(inputs.into_iter(), output, false)),
- }));
+ let fty = tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
+ inputs.into_iter(),
+ output,
+ false,
+ hir::Unsafety::Unsafe,
+ abi
+ )));
let i_n_tps = tcx.item_generics(def_id).types.len();
if i_n_tps != n_tps {
let span = match it.node {
.span_label(span, &format!("expected {} type parameter", n_tps))
.emit();
} else {
- require_same_types(ccx,
+ require_same_types(tcx,
&ObligationCause::new(it.span,
it.id,
ObligationCauseCode::IntrinsicType),
/// Remember to add all intrinsics here, in librustc_trans/trans/intrinsic.rs,
/// and in libcore/intrinsics.rs
-pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
- fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
- let name = Symbol::intern(&format!("P{}", n));
- ccx.tcx.mk_param(n, name)
- }
-
- let tcx = ccx.tcx;
+pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ it: &hir::ForeignItem) {
+ let param = |n| tcx.mk_param(n, Symbol::intern(&format!("P{}", n)));
let name = it.name.as_str();
let (n_tps, inputs, output) = if name.starts_with("atomic_") {
let split : Vec<&str> = name.split('_').collect();
//We only care about the operation here
let (n_tps, inputs, output) = match split[1] {
- "cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)),
- param(ccx, 0),
- param(ccx, 0)],
- tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
- "load" => (1, vec![tcx.mk_imm_ptr(param(ccx, 0))],
- param(ccx, 0)),
- "store" => (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)],
+ "cxchg" | "cxchgweak" => (1, vec![tcx.mk_mut_ptr(param(0)),
+ param(0),
+ param(0)],
+ tcx.intern_tup(&[param(0), tcx.types.bool], false)),
+ "load" => (1, vec![tcx.mk_imm_ptr(param(0))],
+ param(0)),
+ "store" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
tcx.mk_nil()),
"xchg" | "xadd" | "xsub" | "and" | "nand" | "or" | "xor" | "max" |
"min" | "umax" | "umin" => {
- (1, vec![tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)],
- param(ccx, 0))
+ (1, vec![tcx.mk_mut_ptr(param(0)), param(0)],
+ param(0))
}
"fence" | "singlethreadfence" => {
(0, Vec::new(), tcx.mk_nil())
let (n_tps, inputs, output) = match &name[..] {
"breakpoint" => (0, Vec::new(), tcx.mk_nil()),
"size_of" |
- "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.usize),
+ "pref_align_of" | "min_align_of" => (1, Vec::new(), tcx.types.usize),
"size_of_val" | "min_align_of_val" => {
(1, vec![
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
ty::BrAnon(0))),
- param(ccx, 0))
- ], ccx.tcx.types.usize)
+ param(0))
+ ], tcx.types.usize)
}
- "rustc_peek" => (1, vec![param(ccx, 0)], param(ccx, 0)),
- "init" => (1, Vec::new(), param(ccx, 0)),
- "uninit" => (1, Vec::new(), param(ccx, 0)),
- "forget" => (1, vec![ param(ccx, 0) ], tcx.mk_nil()),
- "transmute" => (2, vec![ param(ccx, 0) ], param(ccx, 1)),
+ "rustc_peek" => (1, vec![param(0)], param(0)),
+ "init" => (1, Vec::new(), param(0)),
+ "uninit" => (1, Vec::new(), param(0)),
+ "forget" => (1, vec![ param(0) ], tcx.mk_nil()),
+ "transmute" => (2, vec![ param(0) ], param(1)),
"move_val_init" => {
(1,
vec![
- tcx.mk_mut_ptr(param(ccx, 0)),
- param(ccx, 0)
+ tcx.mk_mut_ptr(param(0)),
+ param(0)
],
tcx.mk_nil())
}
"drop_in_place" => {
- (1, vec![tcx.mk_mut_ptr(param(ccx, 0))], tcx.mk_nil())
+ (1, vec![tcx.mk_mut_ptr(param(0))], tcx.mk_nil())
}
- "needs_drop" => (1, Vec::new(), ccx.tcx.types.bool),
+ "needs_drop" => (1, Vec::new(), tcx.types.bool),
"type_name" => (1, Vec::new(), tcx.mk_static_str()),
- "type_id" => (1, Vec::new(), ccx.tcx.types.u64),
+ "type_id" => (1, Vec::new(), tcx.types.u64),
"offset" | "arith_offset" => {
(1,
vec![
tcx.mk_ptr(ty::TypeAndMut {
- ty: param(ccx, 0),
+ ty: param(0),
mutbl: hir::MutImmutable
}),
- ccx.tcx.types.isize
+ tcx.types.isize
],
tcx.mk_ptr(ty::TypeAndMut {
- ty: param(ccx, 0),
+ ty: param(0),
mutbl: hir::MutImmutable
}))
}
(1,
vec![
tcx.mk_ptr(ty::TypeAndMut {
- ty: param(ccx, 0),
+ ty: param(0),
mutbl: hir::MutImmutable
}),
tcx.mk_ptr(ty::TypeAndMut {
- ty: param(ccx, 0),
+ ty: param(0),
mutbl: hir::MutMutable
}),
tcx.types.usize,
(1,
vec![
tcx.mk_ptr(ty::TypeAndMut {
- ty: param(ccx, 0),
+ ty: param(0),
mutbl: hir::MutMutable
}),
tcx.mk_ptr(ty::TypeAndMut {
- ty: param(ccx, 0),
+ ty: param(0),
mutbl: hir::MutImmutable
}),
tcx.types.usize,
(1,
vec![
tcx.mk_ptr(ty::TypeAndMut {
- ty: param(ccx, 0),
+ ty: param(0),
mutbl: hir::MutMutable
}),
tcx.types.u8,
"roundf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
"volatile_load" =>
- (1, vec![ tcx.mk_imm_ptr(param(ccx, 0)) ], param(ccx, 0)),
+ (1, vec![ tcx.mk_imm_ptr(param(0)) ], param(0)),
"volatile_store" =>
- (1, vec![ tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0) ], tcx.mk_nil()),
+ (1, vec![ tcx.mk_mut_ptr(param(0)), param(0) ], tcx.mk_nil()),
- "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec![param(ccx, 0)], param(ccx, 0)),
+ "ctpop" | "ctlz" | "cttz" | "bswap" => (1, vec![param(0)], param(0)),
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" =>
- (1, vec![param(ccx, 0), param(ccx, 0)],
- tcx.intern_tup(&[param(ccx, 0), tcx.types.bool], false)),
+ (1, vec![param(0), param(0)],
+ tcx.intern_tup(&[param(0), tcx.types.bool], false)),
"unchecked_div" | "unchecked_rem" =>
- (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
+ (1, vec![param(0), param(0)], param(0)),
"overflowing_add" | "overflowing_sub" | "overflowing_mul" =>
- (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
+ (1, vec![param(0), param(0)], param(0)),
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" =>
- (1, vec![param(ccx, 0), param(ccx, 0)], param(ccx, 0)),
+ (1, vec![param(0), param(0)], param(0)),
"assume" => (0, vec![tcx.types.bool], tcx.mk_nil()),
"likely" => (0, vec![tcx.types.bool], tcx.types.bool),
"discriminant_value" => (1, vec![
tcx.mk_imm_ref(tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
ty::BrAnon(0))),
- param(ccx, 0))], tcx.types.u64),
+ param(0))], tcx.types.u64),
"try" => {
let mut_u8 = tcx.mk_mut_ptr(tcx.types.u8);
- let fn_ty = tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- sig: ty::Binder(tcx.mk_fn_sig(iter::once(mut_u8), tcx.mk_nil(), false)),
- });
+ let fn_ty = ty::Binder(tcx.mk_fn_sig(
+ iter::once(mut_u8),
+ tcx.mk_nil(),
+ false,
+ hir::Unsafety::Normal,
+ Abi::Rust,
+ ));
(0, vec![tcx.mk_fn_ptr(fn_ty), mut_u8, mut_u8], tcx.types.i32)
}
};
(n_tps, inputs, output)
};
- equate_intrinsic_type(ccx, it, n_tps, Abi::RustIntrinsic, inputs, output)
+ equate_intrinsic_type(tcx, it, n_tps, Abi::RustIntrinsic, inputs, output)
}
/// Type-check `extern "platform-intrinsic" { ... }` functions.
-pub fn check_platform_intrinsic_type(ccx: &CrateCtxt,
- it: &hir::ForeignItem) {
+pub fn check_platform_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ it: &hir::ForeignItem) {
let param = |n| {
let name = Symbol::intern(&format!("P{}", n));
- ccx.tcx.mk_param(n, name)
+ tcx.mk_param(n, name)
};
- let tcx = ccx.tcx;
let def_id = tcx.hir.local_def_id(it.id);
let i_n_tps = tcx.item_generics(def_id).types.len();
let name = it.name.as_str();
let mut structural_to_nomimal = FxHashMap();
let sig = tcx.item_type(def_id).fn_sig();
- let sig = tcx.no_late_bound_regions(sig).unwrap();
+ let sig = tcx.no_late_bound_regions(&sig).unwrap();
if intr.inputs.len() != sig.inputs().len() {
span_err!(tcx.sess, it.span, E0444,
"platform-specific intrinsic has invalid number of \
}
let input_pairs = intr.inputs.iter().zip(sig.inputs());
for (i, (expected_arg, arg)) in input_pairs.enumerate() {
- match_intrinsic_type_to_type(ccx, &format!("argument {}", i + 1), it.span,
+ match_intrinsic_type_to_type(tcx, &format!("argument {}", i + 1), it.span,
&mut structural_to_nomimal, expected_arg, arg);
}
- match_intrinsic_type_to_type(ccx, "return value", it.span,
+ match_intrinsic_type_to_type(tcx, "return value", it.span,
&mut structural_to_nomimal,
&intr.output, sig.output());
return
}
};
- equate_intrinsic_type(ccx, it, n_tps, Abi::PlatformIntrinsic,
+ equate_intrinsic_type(tcx, it, n_tps, Abi::PlatformIntrinsic,
inputs, output)
}
// walk the expected type and the actual type in lock step, checking they're
// the same, in a kinda-structural way, i.e. `Vector`s have to be simd structs with
// exactly the right element type
-fn match_intrinsic_type_to_type<'tcx, 'a>(
- ccx: &CrateCtxt<'a, 'tcx>,
+fn match_intrinsic_type_to_type<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
position: &str,
span: Span,
structural_to_nominal: &mut FxHashMap<&'a intrinsics::Type, ty::Ty<'tcx>>,
use intrinsics::Type::*;
let simple_error = |real: &str, expected: &str| {
- span_err!(ccx.tcx.sess, span, E0442,
+ span_err!(tcx.sess, span, E0442,
"intrinsic {} has wrong type: found {}, expected {}",
position, real, expected)
};
simple_error(&format!("`{}`", t),
if const_ {"const pointer"} else {"mut pointer"})
}
- match_intrinsic_type_to_type(ccx, position, span, structural_to_nominal,
+ match_intrinsic_type_to_type(tcx, position, span, structural_to_nominal,
inner_expected, ty)
}
_ => simple_error(&format!("`{}`", t), "raw pointer"),
simple_error(&format!("non-simd type `{}`", t), "simd type");
return;
}
- let t_len = t.simd_size(ccx.tcx);
+ let t_len = t.simd_size(tcx);
if len as usize != t_len {
simple_error(&format!("vector with length {}", t_len),
&format!("length {}", len));
return;
}
- let t_ty = t.simd_type(ccx.tcx);
+ let t_ty = t.simd_type(tcx);
{
// check that a given structural type always has the same an intrinsic definition
let previous = structural_to_nominal.entry(expected).or_insert(t);
if *previous != t {
// this gets its own error code because it is non-trivial
- span_err!(ccx.tcx.sess, span, E0443,
+ span_err!(tcx.sess, span, E0443,
"intrinsic {} has wrong type: found `{}`, expected `{}` which \
was used for this vector type previously in this signature",
position,
return;
}
}
- match_intrinsic_type_to_type(ccx,
+ match_intrinsic_type_to_type(tcx,
position,
span,
structural_to_nominal,
return
}
for (e, c) in expected_contents.iter().zip(contents) {
- match_intrinsic_type_to_type(ccx, position, span, structural_to_nominal,
+ match_intrinsic_type_to_type(tcx, position, span, structural_to_nominal,
e, c)
}
}
debug!("method_predicates after subst = {:?}", method_predicates);
- let fty = match self.tcx.item_type(def_id).sty {
- ty::TyFnDef(_, _, f) => f,
- _ => bug!()
- };
+ let sig = self.tcx.item_type(def_id).fn_sig();
// Instantiate late-bound regions and substitute the trait
// parameters into the method type to get the actual method type.
// NB: Instantiate late-bound regions first so that
// `instantiate_type_scheme` can normalize associated types that
// may reference those regions.
- let method_sig = self.replace_late_bound_regions_with_fresh_var(&fty.sig);
+ let method_sig = self.replace_late_bound_regions_with_fresh_var(&sig);
debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
method_sig);
let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
debug!("type scheme substituted, method_sig={:?}", method_sig);
- let method_ty = self.tcx.mk_fn_def(def_id, all_substs,
- self.tcx.mk_bare_fn(ty::BareFnTy {
- sig: ty::Binder(method_sig),
- unsafety: fty.unsafety,
- abi: fty.abi,
- }));
-
- (method_ty, method_predicates)
+ (self.tcx.mk_fn_def(def_id, all_substs, ty::Binder(method_sig)),
+ method_predicates)
}
fn add_obligations(&mut self,
// Disallow calls to the method `drop` defined in the `Drop` trait.
match pick.item.container {
ty::TraitContainer(trait_def_id) => {
- callee::check_legal_trait_for_method_call(self.ccx, self.span, trait_def_id)
+ callee::check_legal_trait_for_method_call(self.tcx, self.span, trait_def_id)
}
ty::ImplContainer(..) => {}
}
if let Some(import_id) = pick.import_id {
let import_def_id = self.tcx.hir.local_def_id(import_id);
debug!("used_trait_import: {:?}", import_def_id);
- self.used_trait_imports.borrow_mut().insert(import_def_id);
+ self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
}
self.tcx.check_stability(pick.item.def_id, call_expr.id, span);
// `instantiate_type_scheme` can normalize associated types that
// may reference those regions.
let original_method_ty = tcx.item_type(def_id);
- let fty = match original_method_ty.sty {
- ty::TyFnDef(_, _, f) => f,
- _ => bug!()
- };
+ let fn_sig = original_method_ty.fn_sig();
let fn_sig = self.replace_late_bound_regions_with_fresh_var(span,
infer::FnCall,
- &fty.sig).0;
+ &fn_sig).0;
let fn_sig = self.instantiate_type_scheme(span, trait_ref.substs, &fn_sig);
let transformed_self_ty = fn_sig.inputs()[0];
let method_ty = tcx.mk_fn_def(def_id, trait_ref.substs,
- tcx.mk_bare_fn(ty::BareFnTy {
- sig: ty::Binder(fn_sig),
- unsafety: fty.unsafety,
- abi: fty.abi
- }));
+ ty::Binder(fn_sig));
debug!("lookup_in_trait_adjusted: matched method method_ty={:?} obligation={:?}",
method_ty,
if let Some(import_id) = pick.import_id {
let import_def_id = self.tcx.hir.local_def_id(import_id);
debug!("used_trait_import: {:?}", import_def_id);
- self.used_trait_imports.borrow_mut().insert(import_def_id);
+ self.tables.borrow_mut().used_trait_imports.insert(import_def_id);
}
let def = pick.item.def();
fn assemble_inherent_impl_candidates_for_type(&mut self, def_id: DefId) {
// Read the inherent implementation candidates for this type from the
// metadata if necessary.
- self.tcx.populate_inherent_implementations_for_type_if_necessary(def_id);
+ self.tcx.populate_inherent_implementations_for_type_if_necessary(self.span, def_id);
- if let Some(impl_infos) = self.tcx.inherent_impls.borrow().get(&def_id) {
+ if let Some(impl_infos) = self.tcx.maps.inherent_impls.borrow().get(&def_id) {
for &impl_def_id in impl_infos.iter() {
self.assemble_inherent_impl_probe(impl_def_id);
}
fn assemble_extension_candidates_for_all_traits(&mut self) -> Result<(), MethodError<'tcx>> {
let mut duplicates = FxHashSet();
- for trait_info in suggest::all_traits(self.ccx) {
+ for trait_info in suggest::all_traits(self.tcx) {
if duplicates.insert(trait_info.def_id) {
self.assemble_extension_candidates_for_trait(None, trait_info.def_id)?;
}
//! Give useful errors and suggestions to users when an item can't be
//! found or is otherwise invalid.
-use CrateCtxt;
-
use check::FnCtxt;
use rustc::hir::map as hir_map;
-use rustc::ty::{self, Ty, ToPolyTraitRef, ToPredicate, TypeFoldable};
+use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable};
use hir::def::Def;
use hir::def_id::{CRATE_DEF_INDEX, DefId};
use middle::lang_items::FnOnceTraitLangItem;
// there's no implemented traits, so lets suggest some traits to
// implement, by finding ones that have the item name, and are
// legal to implement.
- let mut candidates = all_traits(self.ccx)
+ let mut candidates = all_traits(self.tcx)
.filter(|info| {
// we approximate the coherence rules to only suggest
// traits that are legal to implement by requiring that
}
}
-pub type AllTraitsVec = Vec<TraitInfo>;
+pub type AllTraitsVec = Vec<DefId>;
#[derive(Copy, Clone)]
pub struct TraitInfo {
}
/// Retrieve all traits in this crate and any dependent crates.
-pub fn all_traits<'a>(ccx: &'a CrateCtxt) -> AllTraits<'a> {
- if ccx.all_traits.borrow().is_none() {
+pub fn all_traits<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>) -> AllTraits<'a> {
+ if tcx.all_traits.borrow().is_none() {
use rustc::hir::itemlikevisit;
let mut traits = vec![];
match i.node {
hir::ItemTrait(..) => {
let def_id = self.map.local_def_id(i.id);
- self.traits.push(TraitInfo::new(def_id));
+ self.traits.push(def_id);
}
_ => {}
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
- ccx.tcx.hir.krate().visit_all_item_likes(&mut Visitor {
- map: &ccx.tcx.hir,
+ tcx.hir.krate().visit_all_item_likes(&mut Visitor {
+ map: &tcx.hir,
traits: &mut traits,
});
// Cross-crate:
let mut external_mods = FxHashSet();
- fn handle_external_def(ccx: &CrateCtxt,
+ fn handle_external_def(tcx: TyCtxt,
traits: &mut AllTraitsVec,
external_mods: &mut FxHashSet<DefId>,
def: Def) {
let def_id = def.def_id();
match def {
Def::Trait(..) => {
- traits.push(TraitInfo::new(def_id));
+ traits.push(def_id);
}
Def::Mod(..) => {
if !external_mods.insert(def_id) {
return;
}
- for child in ccx.tcx.sess.cstore.item_children(def_id) {
- handle_external_def(ccx, traits, external_mods, child.def)
+ for child in tcx.sess.cstore.item_children(def_id) {
+ handle_external_def(tcx, traits, external_mods, child.def)
}
}
_ => {}
}
}
- for cnum in ccx.tcx.sess.cstore.crates() {
+ for cnum in tcx.sess.cstore.crates() {
let def_id = DefId {
krate: cnum,
index: CRATE_DEF_INDEX,
};
- handle_external_def(ccx, &mut traits, &mut external_mods, Def::Mod(def_id));
+ handle_external_def(tcx, &mut traits, &mut external_mods, Def::Mod(def_id));
}
- *ccx.all_traits.borrow_mut() = Some(traits);
+ *tcx.all_traits.borrow_mut() = Some(traits);
}
- let borrow = ccx.all_traits.borrow();
+ let borrow = tcx.all_traits.borrow();
assert!(borrow.is_some());
AllTraits {
borrow: borrow,
// ugh.
borrow.as_ref().unwrap().get(*idx).map(|info| {
*idx += 1;
- *info
+ TraitInfo::new(*info)
})
}
}
may contain unresolved type variables. After type checking is
complete, the functions in the writeback module are used to take the
types from this table, resolve them, and then write them into their
-permanent home in the type context `ccx.tcx`.
+permanent home in the type context `tcx`.
This means that during inferencing you should use `fcx.write_ty()`
and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::{ParamTy, ParameterEnvironment};
use rustc::ty::{LvaluePreference, NoPreference, PreferMutLvalue};
-use rustc::ty::{self, ToPolyTraitRef, Ty, TyCtxt, Visibility};
+use rustc::ty::{self, Ty, TyCtxt, Visibility};
use rustc::ty::{MethodCall, MethodCallee};
use rustc::ty::adjustment;
use rustc::ty::fold::{BottomUpFolder, TypeFoldable};
+use rustc::ty::maps::Providers;
use rustc::ty::util::{Representability, IntTypeExt};
use require_c_abi_if_variadic;
use session::{Session, CompileResult};
-use CrateCtxt;
use TypeAndSubsts;
use lint;
use util::common::{ErrorReported, indenter};
-use util::nodemap::{DefIdMap, DefIdSet, FxHashMap, FxHashSet, NodeMap};
+use util::nodemap::{DefIdMap, FxHashMap, FxHashSet, NodeMap};
use std::cell::{Cell, RefCell};
use std::cmp;
use std::ops::{self, Deref};
use syntax::abi::Abi;
use syntax::ast;
-use syntax::attr;
use syntax::codemap::{self, original_sp, Spanned};
use syntax::feature_gate::{GateIssue, emit_feature_err};
use syntax::ptr::P;
use rustc::middle::lang_items;
use rustc_back::slice;
use rustc_const_eval::eval_length;
+use rustc_const_math::ConstInt;
mod assoc;
mod autoderef;
/// `bar()` will each have their own `FnCtxt`, but they will
/// share the inherited fields.
pub struct Inherited<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- ccx: &'a CrateCtxt<'a, 'gcx>,
infcx: InferCtxt<'a, 'gcx, 'tcx>,
+
locals: RefCell<NodeMap<Ty<'tcx>>>,
fulfillment_cx: RefCell<traits::FulfillmentContext<'tcx>>,
// associated fresh inference variable. Writeback resolves these
// variables to get the concrete type, which can be used to
// deanonymize TyAnon, after typeck is done with all functions.
- anon_types: RefCell<DefIdMap<Ty<'tcx>>>,
-
- // Obligations which will have to be checked at the end of
- // type-checking, after all functions have been inferred.
- deferred_obligations: RefCell<Vec<traits::DeferredObligation<'tcx>>>,
-
- // a set of trait import def-ids that we use during method
- // resolution; during writeback, this is written into
- // `tcx.used_trait_imports` for this item def-id
- used_trait_imports: RefCell<FxHashSet<DefId>>,
+ anon_types: RefCell<NodeMap<Ty<'tcx>>>,
}
impl<'a, 'gcx, 'tcx> Deref for Inherited<'a, 'gcx, 'tcx> {
}
impl<'gcx, 'tcx> EnclosingLoops<'gcx, 'tcx> {
- fn find_loop(&mut self, id: Option<ast::NodeId>) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
- if let Some(id) = id {
- if let Some(ix) = self.by_id.get(&id).cloned() {
- Some(&mut self.stack[ix])
- } else {
- None
- }
+ fn find_loop(&mut self, id: hir::LoopIdResult) -> Option<&mut LoopCtxt<'gcx, 'tcx>> {
+ let id_res: Result<_,_> = id.into();
+ if let Some(ix) = id_res.ok().and_then(|id| self.by_id.get(&id).cloned()) {
+ Some(&mut self.stack[ix])
} else {
- self.stack.last_mut()
+ None
}
}
}
body_id: ast::NodeId,
- // This flag is set to true if, during the writeback phase, we encounter
- // a type error in this function.
- writeback_errors: Cell<bool>,
-
// Number of errors that had been reported when we started
// checking this function. On exit, if we find that *more* errors
// have been reported, we will skip regionck and other work that
}
}
-/// Helper type of a temporary returned by ccx.inherited(...).
+/// Helper type of a temporary returned by Inherited::build(...).
/// Necessary because we can't write the following bound:
/// F: for<'b, 'tcx> where 'gcx: 'tcx FnOnce(Inherited<'b, 'gcx, 'tcx>).
pub struct InheritedBuilder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
- ccx: &'a CrateCtxt<'a, 'gcx>,
infcx: infer::InferCtxtBuilder<'a, 'gcx, 'tcx>
}
-impl<'a, 'gcx, 'tcx> CrateCtxt<'a, 'gcx> {
- pub fn inherited(&'a self, id: ast::NodeId)
- -> InheritedBuilder<'a, 'gcx, 'tcx> {
+impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
+ pub fn build(tcx: TyCtxt<'a, 'gcx, 'gcx>, id: ast::NodeId)
+ -> InheritedBuilder<'a, 'gcx, 'tcx> {
let tables = ty::TypeckTables::empty();
- let param_env = ParameterEnvironment::for_item(self.tcx, id);
+ let param_env = ParameterEnvironment::for_item(tcx, id);
InheritedBuilder {
- ccx: self,
- infcx: self.tcx.infer_ctxt((tables, param_env), Reveal::NotSpecializable)
+ infcx: tcx.infer_ctxt((tables, param_env), Reveal::UserFacing)
}
}
}
fn enter<F, R>(&'tcx mut self, f: F) -> R
where F: for<'b> FnOnce(Inherited<'b, 'gcx, 'tcx>) -> R
{
- let ccx = self.ccx;
- self.infcx.enter(|infcx| f(Inherited::new(ccx, infcx)))
+ self.infcx.enter(|infcx| f(Inherited::new(infcx)))
}
}
impl<'a, 'gcx, 'tcx> Inherited<'a, 'gcx, 'tcx> {
- pub fn new(ccx: &'a CrateCtxt<'a, 'gcx>,
- infcx: InferCtxt<'a, 'gcx, 'tcx>)
- -> Self {
+ pub fn new(infcx: InferCtxt<'a, 'gcx, 'tcx>) -> Self {
Inherited {
- ccx: ccx,
infcx: infcx,
fulfillment_cx: RefCell::new(traits::FulfillmentContext::new()),
locals: RefCell::new(NodeMap()),
deferred_call_resolutions: RefCell::new(DefIdMap()),
deferred_cast_checks: RefCell::new(Vec::new()),
- anon_types: RefCell::new(DefIdMap()),
- deferred_obligations: RefCell::new(Vec::new()),
- used_trait_imports: RefCell::new(DefIdSet()),
+ anon_types: RefCell::new(NodeMap()),
}
}
}
-struct CheckItemTypesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
-struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { ccx: &'a CrateCtxt<'a, 'tcx> }
+struct CheckItemTypesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
+struct CheckItemBodiesVisitor<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx> }
impl<'a, 'tcx> Visitor<'tcx> for CheckItemTypesVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::OnlyBodies(&self.ccx.tcx.hir)
+ NestedVisitorMap::OnlyBodies(&self.tcx.hir)
}
fn visit_item(&mut self, i: &'tcx hir::Item) {
- check_item_type(self.ccx, i);
+ check_item_type(self.tcx, i);
intravisit::walk_item(self, i);
}
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
match t.node {
hir::TyArray(_, length) => {
- check_const_with_type(self.ccx, length, self.ccx.tcx.types.usize, length.node_id);
+ self.tcx.item_tables(self.tcx.hir.local_def_id(length.node_id));
}
_ => {}
}
fn visit_expr(&mut self, e: &'tcx hir::Expr) {
match e.node {
hir::ExprRepeat(_, count) => {
- check_const_with_type(self.ccx, count, self.ccx.tcx.types.usize, count.node_id);
+ self.tcx.item_tables(self.tcx.hir.local_def_id(count.node_id));
}
_ => {}
}
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
- hir::ItemFn(ref decl, .., body_id) => {
- check_bare_fn(self.ccx, &decl, body_id, item.id, item.span);
+ hir::ItemFn(..) => {
+ self.tcx.item_tables(self.tcx.hir.local_def_id(item.id));
}
_ => { }
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
match trait_item.node {
- hir::TraitItemKind::Const(_, Some(expr)) => {
- check_const(self.ccx, expr, trait_item.id)
- }
- hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
- check_bare_fn(self.ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
+ hir::TraitItemKind::Const(_, Some(_)) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
+ self.tcx.item_tables(self.tcx.hir.local_def_id(trait_item.id));
}
hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
hir::TraitItemKind::Const(_, None) |
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
match impl_item.node {
- hir::ImplItemKind::Const(_, expr) => {
- check_const(self.ccx, expr, impl_item.id)
- }
- hir::ImplItemKind::Method(ref sig, body_id) => {
- check_bare_fn(self.ccx, &sig.decl, body_id, impl_item.id, impl_item.span);
+ hir::ImplItemKind::Const(..) |
+ hir::ImplItemKind::Method(..) => {
+ self.tcx.item_tables(self.tcx.hir.local_def_id(impl_item.id));
}
hir::ImplItemKind::Type(_) => {
// Nothing to do here.
}
}
-pub fn check_wf_new(ccx: &CrateCtxt) -> CompileResult {
- ccx.tcx.sess.track_errors(|| {
- let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(ccx);
- ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor());
+pub fn check_wf_new<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+ tcx.sess.track_errors(|| {
+ let mut visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx);
+ tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut visit.as_deep_visitor());
})
}
-pub fn check_item_types(ccx: &CrateCtxt) -> CompileResult {
- ccx.tcx.sess.track_errors(|| {
- let mut visit = CheckItemTypesVisitor { ccx: ccx };
- ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
+pub fn check_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+ tcx.sess.track_errors(|| {
+ let mut visit = CheckItemTypesVisitor { tcx: tcx };
+ tcx.visit_all_item_likes_in_krate(DepNode::TypeckItemType,
&mut visit.as_deep_visitor());
})
}
-pub fn check_item_bodies(ccx: &CrateCtxt) -> CompileResult {
- ccx.tcx.sess.track_errors(|| {
- let mut visit = CheckItemBodiesVisitor { ccx: ccx };
- ccx.tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
-
- // Process deferred obligations, now that all functions
- // bodies have been fully inferred.
- for (&item_id, obligations) in ccx.deferred_obligations.borrow().iter() {
- // Use the same DepNode as for the body of the original function/item.
- let def_id = ccx.tcx.hir.local_def_id(item_id);
- let _task = ccx.tcx.dep_graph.in_task(DepNode::TypeckTables(def_id));
-
- let param_env = ParameterEnvironment::for_item(ccx.tcx, item_id);
- ccx.tcx.infer_ctxt(param_env, Reveal::NotSpecializable).enter(|infcx| {
- let mut fulfillment_cx = traits::FulfillmentContext::new();
- for obligation in obligations.iter().map(|o| o.to_obligation()) {
- fulfillment_cx.register_predicate_obligation(&infcx, obligation);
- }
-
- if let Err(errors) = fulfillment_cx.select_all_or_error(&infcx) {
- infcx.report_fulfillment_errors(&errors);
- }
- });
- }
+pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+ tcx.sess.track_errors(|| {
+ let mut visit = CheckItemBodiesVisitor { tcx: tcx };
+ tcx.visit_all_item_likes_in_krate(DepNode::TypeckTables, &mut visit);
})
}
-pub fn check_drop_impls(ccx: &CrateCtxt) -> CompileResult {
- ccx.tcx.sess.track_errors(|| {
- let _task = ccx.tcx.dep_graph.in_task(DepNode::Dropck);
- let drop_trait = match ccx.tcx.lang_items.drop_trait() {
- Some(id) => ccx.tcx.lookup_trait_def(id), None => { return }
+pub fn check_drop_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
+ tcx.sess.track_errors(|| {
+ let _task = tcx.dep_graph.in_task(DepNode::Dropck);
+ let drop_trait = match tcx.lang_items.drop_trait() {
+ Some(id) => tcx.lookup_trait_def(id), None => { return }
};
- drop_trait.for_each_impl(ccx.tcx, |drop_impl_did| {
- let _task = ccx.tcx.dep_graph.in_task(DepNode::DropckImpl(drop_impl_did));
+ drop_trait.for_each_impl(tcx, |drop_impl_did| {
+ let _task = tcx.dep_graph.in_task(DepNode::DropckImpl(drop_impl_did));
if drop_impl_did.is_local() {
- match dropck::check_drop_impl(ccx, drop_impl_did) {
+ match dropck::check_drop_impl(tcx, drop_impl_did) {
Ok(()) => {}
Err(()) => {
- assert!(ccx.tcx.sess.has_errors());
+ assert!(tcx.sess.has_errors());
}
}
}
})
}
-fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- decl: &'tcx hir::FnDecl,
- body_id: hir::BodyId,
- fn_id: ast::NodeId,
- span: Span) {
- let body = ccx.tcx.hir.body(body_id);
-
- let raw_fty = ccx.tcx.item_type(ccx.tcx.hir.local_def_id(fn_id));
- let fn_ty = match raw_fty.sty {
- ty::TyFnDef(.., f) => f,
- _ => span_bug!(body.value.span, "check_bare_fn: function type expected")
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ typeck_tables,
+ closure_type,
+ closure_kind,
+ ..*providers
};
+}
- check_abi(ccx, span, fn_ty.abi);
+fn closure_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> ty::PolyFnSig<'tcx> {
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ tcx.item_tables(def_id).closure_tys[&node_id]
+}
- ccx.inherited(fn_id).enter(|inh| {
- // Compute the fty from point of view of inside fn.
- let fn_scope = inh.tcx.region_maps.call_site_extent(fn_id, body_id.node_id);
- let fn_sig =
- fn_ty.sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
- let fn_sig =
- inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
- let fn_sig =
- inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
+fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> ty::ClosureKind {
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ tcx.item_tables(def_id).closure_kinds[&node_id]
+}
+
+fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> &'tcx ty::TypeckTables<'tcx> {
+ // Closures' tables come from their outermost function,
+ // as they are part of the same "inference environment".
+ let outer_def_id = tcx.closure_base_def_id(def_id);
+ if outer_def_id != def_id {
+ return tcx.item_tables(outer_def_id);
+ }
+
+ let id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let span = tcx.hir.span(id);
+ let unsupported = || {
+ span_bug!(span, "can't type-check body of {:?}", def_id);
+ };
- let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
+ // Figure out what primary body this item has.
+ let mut fn_decl = None;
+ let body_id = match tcx.hir.get(id) {
+ hir::map::NodeItem(item) => {
+ match item.node {
+ hir::ItemConst(_, body) |
+ hir::ItemStatic(_, _, body) => body,
+ hir::ItemFn(ref decl, .., body) => {
+ fn_decl = Some(decl);
+ body
+ }
+ _ => unsupported()
+ }
+ }
+ hir::map::NodeTraitItem(item) => {
+ match item.node {
+ hir::TraitItemKind::Const(_, Some(body)) => body,
+ hir::TraitItemKind::Method(ref sig,
+ hir::TraitMethod::Provided(body)) => {
+ fn_decl = Some(&sig.decl);
+ body
+ }
+ _ => unsupported()
+ }
+ }
+ hir::map::NodeImplItem(item) => {
+ match item.node {
+ hir::ImplItemKind::Const(_, body) => body,
+ hir::ImplItemKind::Method(ref sig, body) => {
+ fn_decl = Some(&sig.decl);
+ body
+ }
+ _ => unsupported()
+ }
+ }
+ hir::map::NodeExpr(expr) => {
+ // FIXME(eddyb) Closures should have separate
+ // function definition IDs and expression IDs.
+ // Type-checking should not let closures get
+ // this far in a constant position.
+ // Assume that everything other than closures
+ // is a constant "initializer" expression.
+ match expr.node {
+ hir::ExprClosure(..) => {
+ // We should've bailed out above for closures.
+ span_bug!(expr.span, "unexpected closure")
+ }
+ _ => hir::BodyId { node_id: expr.id }
+ }
+ }
+ _ => unsupported()
+ };
+ let body = tcx.hir.body(body_id);
+
+ Inherited::build(tcx, id).enter(|inh| {
+ let fcx = if let Some(decl) = fn_decl {
+ let fn_sig = tcx.item_type(def_id).fn_sig();
+
+ check_abi(tcx, span, fn_sig.abi());
+
+ // Compute the fty from point of view of inside fn.
+ let fn_scope = inh.tcx.region_maps.call_site_extent(id, body_id.node_id);
+ let fn_sig =
+ fn_sig.subst(inh.tcx, &inh.parameter_environment.free_substs);
+ let fn_sig =
+ inh.tcx.liberate_late_bound_regions(fn_scope, &fn_sig);
+ let fn_sig =
+ inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
+
+ check_fn(&inh, fn_sig, decl, id, body)
+ } else {
+ let expected_type = tcx.item_type(def_id);
+ let fcx = FnCtxt::new(&inh, None, body.value.id);
+ fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
+
+ // Gather locals in statics (because of block expressions).
+ // This is technically unnecessary because locals in static items are forbidden,
+ // but prevents type checking from blowing up before const checking can properly
+ // emit an error.
+ GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
+
+ fcx.check_expr_coercable_to_type(&body.value, expected_type);
+
+ fcx
+ };
fcx.select_all_obligations_and_apply_defaults();
fcx.closure_analyze(body);
fcx.select_obligations_where_possible();
fcx.check_casts();
- fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
+ fcx.select_all_obligations_or_error();
+
+ if fn_decl.is_some() {
+ fcx.regionck_fn(id, body);
+ } else {
+ fcx.regionck_expr(body);
+ }
- fcx.regionck_fn(fn_id, body);
- fcx.resolve_type_vars_in_body(body);
- });
+ fcx.resolve_type_vars_in_body(body)
+ })
}
-fn check_abi<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, abi: Abi) {
- if !ccx.tcx.sess.target.target.is_abi_supported(abi) {
- struct_span_err!(ccx.tcx.sess, span, E0570,
+fn check_abi<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, abi: Abi) {
+ if !tcx.sess.target.target.is_abi_supported(abi) {
+ struct_span_err!(tcx.sess, span, E0570,
"The ABI `{}` is not supported for the current target", abi).emit()
}
}
_: hir::BodyId, _: Span, _: ast::NodeId) { }
}
-/// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
+/// Helper used for fns and closures. Does the grungy work of checking a function
/// body and returns the function context used for that purpose, since in the case of a fn item
/// there is still a bit more to do.
///
/// * ...
/// * inherited: other fields inherited from the enclosing fn (if any)
fn check_fn<'a, 'gcx, 'tcx>(inherited: &'a Inherited<'a, 'gcx, 'tcx>,
- unsafety: hir::Unsafety,
- unsafety_id: ast::NodeId,
- fn_sig: &ty::FnSig<'tcx>,
+ fn_sig: ty::FnSig<'tcx>,
decl: &'gcx hir::FnDecl,
fn_id: ast::NodeId,
body: &'gcx hir::Body)
// in the case of function expressions, based on the outer context.
let mut fcx = FnCtxt::new(inherited, None, body.value.id);
let ret_ty = fn_sig.output();
- *fcx.ps.borrow_mut() = UnsafetyState::function(unsafety, unsafety_id);
+ *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id);
fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType);
fcx.ret_ty = fcx.instantiate_anon_types(&Some(ret_ty));
- fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(),
- fn_sig.variadic);
+ fn_sig = fcx.tcx.mk_fn_sig(
+ fn_sig.inputs().iter().cloned(),
+ fcx.ret_ty.unwrap(),
+ fn_sig.variadic,
+ fn_sig.unsafety,
+ fn_sig.abi
+ );
GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
fcx
}
-fn check_struct(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
- let def_id = ccx.tcx.hir.local_def_id(id);
- check_representable(ccx.tcx, span, def_id);
+fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ id: ast::NodeId,
+ span: Span) {
+ let def_id = tcx.hir.local_def_id(id);
+ check_representable(tcx, span, def_id);
- if ccx.tcx.lookup_simd(def_id) {
- check_simd(ccx.tcx, span, def_id);
+ if tcx.lookup_adt_def(def_id).repr.simd {
+ check_simd(tcx, span, def_id);
}
}
-fn check_union(ccx: &CrateCtxt, id: ast::NodeId, span: Span) {
- check_representable(ccx.tcx, span, ccx.tcx.hir.local_def_id(id));
+fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ id: ast::NodeId,
+ span: Span) {
+ check_representable(tcx, span, tcx.hir.local_def_id(id));
}
-pub fn check_item_type<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>, it: &'tcx hir::Item) {
+pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
debug!("check_item_type(it.id={}, it.name={})",
it.id,
- ccx.tcx.item_path_str(ccx.tcx.hir.local_def_id(it.id)));
+ tcx.item_path_str(tcx.hir.local_def_id(it.id)));
let _indenter = indenter();
match it.node {
// Consts can play a role in type-checking, so they are included here.
- hir::ItemStatic(.., e) |
- hir::ItemConst(_, e) => check_const(ccx, e, it.id),
+ hir::ItemStatic(..) |
+ hir::ItemConst(..) => {
+ tcx.item_tables(tcx.hir.local_def_id(it.id));
+ }
hir::ItemEnum(ref enum_definition, _) => {
- check_enum_variants(ccx,
+ check_enum_variants(tcx,
it.span,
&enum_definition.variants,
it.id);
hir::ItemFn(..) => {} // entirely within check_item_body
hir::ItemImpl(.., ref impl_item_refs) => {
debug!("ItemImpl {} with id {}", it.name, it.id);
- let impl_def_id = ccx.tcx.hir.local_def_id(it.id);
- if let Some(impl_trait_ref) = ccx.tcx.impl_trait_ref(impl_def_id) {
- check_impl_items_against_trait(ccx,
+ let impl_def_id = tcx.hir.local_def_id(it.id);
+ if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+ check_impl_items_against_trait(tcx,
it.span,
impl_def_id,
impl_trait_ref,
impl_item_refs);
let trait_def_id = impl_trait_ref.def_id;
- check_on_unimplemented(ccx, trait_def_id, it);
+ check_on_unimplemented(tcx, trait_def_id, it);
}
}
hir::ItemTrait(..) => {
- let def_id = ccx.tcx.hir.local_def_id(it.id);
- check_on_unimplemented(ccx, def_id, it);
+ let def_id = tcx.hir.local_def_id(it.id);
+ check_on_unimplemented(tcx, def_id, it);
}
hir::ItemStruct(..) => {
- check_struct(ccx, it.id, it.span);
+ check_struct(tcx, it.id, it.span);
}
hir::ItemUnion(..) => {
- check_union(ccx, it.id, it.span);
+ check_union(tcx, it.id, it.span);
}
hir::ItemTy(_, ref generics) => {
- let def_id = ccx.tcx.hir.local_def_id(it.id);
- let pty_ty = ccx.tcx.item_type(def_id);
- check_bounds_are_used(ccx, generics, pty_ty);
+ let def_id = tcx.hir.local_def_id(it.id);
+ let pty_ty = tcx.item_type(def_id);
+ check_bounds_are_used(tcx, generics, pty_ty);
}
hir::ItemForeignMod(ref m) => {
- check_abi(ccx, it.span, m.abi);
+ check_abi(tcx, it.span, m.abi);
if m.abi == Abi::RustIntrinsic {
for item in &m.items {
- intrinsic::check_intrinsic_type(ccx, item);
+ intrinsic::check_intrinsic_type(tcx, item);
}
} else if m.abi == Abi::PlatformIntrinsic {
for item in &m.items {
- intrinsic::check_platform_intrinsic_type(ccx, item);
+ intrinsic::check_platform_intrinsic_type(tcx, item);
}
} else {
for item in &m.items {
- let generics = ccx.tcx.item_generics(ccx.tcx.hir.local_def_id(item.id));
+ let generics = tcx.item_generics(tcx.hir.local_def_id(item.id));
if !generics.types.is_empty() {
- let mut err = struct_span_err!(ccx.tcx.sess, item.span, E0044,
+ let mut err = struct_span_err!(tcx.sess, item.span, E0044,
"foreign items may not have type parameters");
span_help!(&mut err, item.span,
"consider using specialization instead of \
}
if let hir::ForeignItemFn(ref fn_decl, _, _) = item.node {
- require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
+ require_c_abi_if_variadic(tcx, fn_decl, m.abi, item.span);
}
}
}
}
}
-fn check_on_unimplemented<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn check_on_unimplemented<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
item: &hir::Item) {
- let generics = ccx.tcx.item_generics(def_id);
+ let generics = tcx.item_generics(def_id);
if let Some(ref attr) = item.attrs.iter().find(|a| {
a.check_name("rustc_on_unimplemented")
}) {
}) {
Some(_) => (),
None => {
- let name = ccx.tcx.item_name(def_id);
- span_err!(ccx.tcx.sess, attr.span, E0230,
+ let name = tcx.item_name(def_id);
+ span_err!(tcx.sess, attr.span, E0230,
"there is no type parameter \
{} on trait {}",
s, name);
},
// `{:1}` and `{}` are not to be used
Position::ArgumentIs(_) => {
- span_err!(ccx.tcx.sess, attr.span, E0231,
+ span_err!(tcx.sess, attr.span, E0231,
"only named substitution \
parameters are allowed");
}
}
} else {
struct_span_err!(
- ccx.tcx.sess, attr.span, E0232,
+ tcx.sess, attr.span, E0232,
"this attribute must have a value")
.span_label(attr.span, &format!("attribute requires a value"))
.note(&format!("eg `#[rustc_on_unimplemented = \"foo\"]`"))
}
-fn check_impl_items_against_trait<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn check_impl_items_against_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_span: Span,
impl_id: DefId,
impl_trait_ref: ty::TraitRef<'tcx>,
if impl_trait_ref.references_error() { return; }
// Locate trait definition and items
- let tcx = ccx.tcx;
let trait_def = tcx.lookup_trait_def(impl_trait_ref.def_id);
let mut overridden_associated_type = None;
- let impl_items = || impl_item_refs.iter().map(|iiref| ccx.tcx.hir.impl_item(iiref.id));
+ let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir.impl_item(iiref.id));
// Check existing impl methods to see if they are both present in trait
// and compatible with trait signature
hir::ImplItemKind::Const(..) => {
// Find associated const definition.
if ty_trait_item.kind == ty::AssociatedKind::Const {
- compare_const_impl(ccx,
+ compare_const_impl(tcx,
&ty_impl_item,
impl_item.span,
&ty_trait_item,
let trait_span = tcx.hir.span_if_local(ty_trait_item.def_id);
if ty_trait_item.kind == ty::AssociatedKind::Method {
let err_count = tcx.sess.err_count();
- compare_impl_method(ccx,
+ compare_impl_method(tcx,
&ty_impl_item,
impl_item.span,
body_id.node_id,
true); // start with old-broken-mode
if err_count == tcx.sess.err_count() {
// old broken mode did not report an error. Try with the new mode.
- compare_impl_method(ccx,
+ compare_impl_method(tcx,
&ty_impl_item,
impl_item.span,
body_id.node_id,
}
}
-/// Checks a constant with a given type.
-fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
- body: hir::BodyId,
- expected_type: Ty<'tcx>,
- id: ast::NodeId) {
- let body = ccx.tcx.hir.body(body);
- ccx.inherited(id).enter(|inh| {
- let fcx = FnCtxt::new(&inh, None, body.value.id);
- fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
-
- // Gather locals in statics (because of block expressions).
- // This is technically unnecessary because locals in static items are forbidden,
- // but prevents type checking from blowing up before const checking can properly
- // emit an error.
- GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
-
- fcx.check_expr_coercable_to_type(&body.value, expected_type);
-
- fcx.select_all_obligations_and_apply_defaults();
- fcx.closure_analyze(body);
- fcx.select_obligations_where_possible();
- fcx.check_casts();
- fcx.select_all_obligations_or_error();
-
- fcx.regionck_expr(body);
- fcx.resolve_type_vars_in_body(body);
- });
-}
-
-fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
- body: hir::BodyId,
- id: ast::NodeId) {
- let decl_ty = ccx.tcx.item_type(ccx.tcx.hir.local_def_id(id));
- check_const_with_type(ccx, body, decl_ty, id);
-}
-
/// Checks whether a type can be represented in memory. In particular, it
/// identifies types that contain themselves without indirection through a
/// pointer, which would mean their size is unbounded.
}
#[allow(trivial_numeric_casts)]
-pub fn check_enum_variants<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
- sp: Span,
- vs: &'tcx [hir::Variant],
- id: ast::NodeId) {
- let def_id = ccx.tcx.hir.local_def_id(id);
- let hint = *ccx.tcx.lookup_repr_hints(def_id).get(0).unwrap_or(&attr::ReprAny);
-
- if hint != attr::ReprAny && vs.is_empty() {
+pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ sp: Span,
+ vs: &'tcx [hir::Variant],
+ id: ast::NodeId) {
+ let def_id = tcx.hir.local_def_id(id);
+ let def = tcx.lookup_adt_def(def_id);
+
+ if vs.is_empty() && tcx.has_attr(def_id, "repr") {
struct_span_err!(
- ccx.tcx.sess, sp, E0084,
+ tcx.sess, sp, E0084,
"unsupported representation for zero-variant enum")
.span_label(sp, &format!("unsupported enum representation"))
.emit();
}
- let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
- if repr_type_ty == ccx.tcx.types.i128 || repr_type_ty == ccx.tcx.types.u128 {
- if !ccx.tcx.sess.features.borrow().i128_type {
- emit_feature_err(&ccx.tcx.sess.parse_sess,
+ let repr_type_ty = def.repr.discr_type().to_ty(tcx);
+ if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 {
+ if !tcx.sess.features.borrow().i128_type {
+ emit_feature_err(&tcx.sess.parse_sess,
"i128_type", sp, GateIssue::Language, "128-bit type is unstable");
}
}
for v in vs {
if let Some(e) = v.node.disr_expr {
- check_const_with_type(ccx, e, repr_type_ty, e.node_id);
+ tcx.item_tables(tcx.hir.local_def_id(e.node_id));
}
}
- let def_id = ccx.tcx.hir.local_def_id(id);
-
- let variants = &ccx.tcx.lookup_adt_def(def_id).variants;
- let mut disr_vals: Vec<ty::Disr> = Vec::new();
- for (v, variant) in vs.iter().zip(variants.iter()) {
- let current_disr_val = variant.disr_val;
-
+ let mut disr_vals: Vec<ConstInt> = Vec::new();
+ for (discr, v) in def.discriminants(tcx).zip(vs) {
// Check for duplicate discriminant values
- if let Some(i) = disr_vals.iter().position(|&x| x == current_disr_val) {
- let variant_i_node_id = ccx.tcx.hir.as_local_node_id(variants[i].did).unwrap();
- let variant_i = ccx.tcx.hir.expect_variant(variant_i_node_id);
+ if let Some(i) = disr_vals.iter().position(|&x| x == discr) {
+ let variant_i_node_id = tcx.hir.as_local_node_id(def.variants[i].did).unwrap();
+ let variant_i = tcx.hir.expect_variant(variant_i_node_id);
let i_span = match variant_i.node.disr_expr {
- Some(expr) => ccx.tcx.hir.span(expr.node_id),
- None => ccx.tcx.hir.span(variant_i_node_id)
+ Some(expr) => tcx.hir.span(expr.node_id),
+ None => tcx.hir.span(variant_i_node_id)
};
let span = match v.node.disr_expr {
- Some(expr) => ccx.tcx.hir.span(expr.node_id),
+ Some(expr) => tcx.hir.span(expr.node_id),
None => v.span
};
- struct_span_err!(ccx.tcx.sess, span, E0081,
+ struct_span_err!(tcx.sess, span, E0081,
"discriminant value `{}` already exists", disr_vals[i])
.span_label(i_span, &format!("first use of `{}`", disr_vals[i]))
.span_label(span , &format!("enum already has `{}`", disr_vals[i]))
.emit();
}
- disr_vals.push(current_disr_val);
+ disr_vals.push(discr);
}
- check_representable(ccx.tcx, sp, def_id);
+ check_representable(tcx, sp, def_id);
}
impl<'a, 'gcx, 'tcx> AstConv<'gcx, 'tcx> for FnCtxt<'a, 'gcx, 'tcx> {
&self.ast_ty_to_ty_cache
}
- fn get_generics(&self, _: Span, id: DefId)
- -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>
- {
- Ok(self.tcx().item_generics(id))
- }
-
- fn get_item_type(&self, _: Span, id: DefId) -> Result<Ty<'tcx>, ErrorReported>
- {
- Ok(self.tcx().item_type(id))
- }
-
- fn get_trait_def(&self, _: Span, id: DefId)
- -> Result<&'tcx ty::TraitDef, ErrorReported>
- {
- Ok(self.tcx().lookup_trait_def(id))
- }
-
- fn ensure_super_predicates(&self, _: Span, _: DefId) -> Result<(), ErrorReported> {
- // all super predicates are ensured during collect pass
- Ok(())
- }
-
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
Some(&self.parameter_environment.free_substs)
}
- fn get_type_parameter_bounds(&self,
- _: Span,
- node_id: ast::NodeId)
- -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+ fn get_type_parameter_bounds(&self, _: Span, def_id: DefId)
+ -> ty::GenericPredicates<'tcx>
{
- let def = self.tcx.type_parameter_def(node_id);
- let r = self.parameter_environment
- .caller_bounds
- .iter()
- .filter_map(|predicate| {
- match *predicate {
- ty::Predicate::Trait(ref data) => {
- if data.0.self_ty().is_param(def.index) {
- Some(data.to_poly_trait_ref())
- } else {
- None
- }
- }
- _ => {
- None
- }
- }
- })
- .collect();
- Ok(r)
+ let tcx = self.tcx;
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let item_id = tcx.hir.ty_param_owner(node_id);
+ let item_def_id = tcx.hir.local_def_id(item_id);
+ let generics = tcx.item_generics(item_def_id);
+ let index = generics.type_param_to_index[&def_id.index];
+ ty::GenericPredicates {
+ parent: None,
+ predicates: self.parameter_environment.caller_bounds.iter().filter(|predicate| {
+ match **predicate {
+ ty::Predicate::Trait(ref data) => {
+ data.0.self_ty().is_param(index)
+ }
+ _ => false
+ }
+ }).cloned().collect()
+ }
}
fn re_infer(&self, span: Span, def: Option<&ty::RegionParameterDef>)
}
fn ty_infer_for_def(&self,
- ty_param_def: &ty::TypeParameterDef<'tcx>,
+ ty_param_def: &ty::TypeParameterDef,
substs: &[Kind<'tcx>],
span: Span) -> Ty<'tcx> {
self.type_var_for_def(span, ty_param_def, substs)
FnCtxt {
ast_ty_to_ty_cache: RefCell::new(NodeMap()),
body_id: body_id,
- writeback_errors: Cell::new(false),
err_count_on_creation: inh.tcx.sess.err_count(),
ret_ty: rty,
ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal,
}
}
- pub fn param_env(&self) -> &ty::ParameterEnvironment<'gcx> {
- &self.parameter_environment
- }
-
pub fn sess(&self) -> &Session {
&self.tcx.sess
}
if ty.references_error() {
self.has_errors.set(true);
+ self.set_tainted_by_errors();
}
// FIXME(canndrew): This is_never should probably be an is_uninhabited
if let ty::TyAnon(def_id, substs) = ty.sty {
// Use the same type variable if the exact same TyAnon appears more
// than once in the return type (e.g. if it's pased to a type alias).
- if let Some(ty_var) = self.anon_types.borrow().get(&def_id) {
+ let id = self.tcx.hir.as_local_node_id(def_id).unwrap();
+ if let Some(ty_var) = self.anon_types.borrow().get(&id) {
return ty_var;
}
let span = self.tcx.def_span(def_id);
let ty_var = self.next_ty_var(TypeVariableOrigin::TypeInference(span));
- self.anon_types.borrow_mut().insert(def_id, ty_var);
+ self.anon_types.borrow_mut().insert(id, ty_var);
let item_predicates = self.tcx.item_predicates(def_id);
let bounds = item_predicates.instantiate(self.tcx, substs);
self.write_ty(node_id, self.tcx.mk_nil());
}
- pub fn write_never(&self, node_id: ast::NodeId) {
- self.write_ty(node_id, self.tcx.types.never);
- }
-
pub fn write_error(&self, node_id: ast::NodeId) {
self.write_ty(node_id, self.tcx.types.err);
}
let mut fulfillment_cx = self.fulfillment_cx.borrow_mut();
- // Steal the deferred obligations before the fulfillment
- // context can turn all of them into errors.
- let obligations = fulfillment_cx.take_deferred_obligations();
- self.deferred_obligations.borrow_mut().extend(obligations);
-
match fulfillment_cx.select_all_or_error(self) {
Ok(()) => { }
Err(errors) => { self.report_fulfillment_errors(&errors); }
let expected_arg_tys = self.expected_types_for_fn_args(
sp,
expected,
- fty.sig.0.output(),
- &fty.sig.0.inputs()[1..]
+ fty.0.output(),
+ &fty.0.inputs()[1..]
);
- self.check_argument_types(sp, &fty.sig.0.inputs()[1..], &expected_arg_tys[..],
- args_no_rcvr, fty.sig.0.variadic, tuple_arguments,
+ self.check_argument_types(sp, &fty.0.inputs()[1..], &expected_arg_tys[..],
+ args_no_rcvr, fty.0.variadic, tuple_arguments,
self.tcx.hir.span_if_local(def_id));
- fty.sig.0.output()
+ fty.0.output()
}
_ => {
span_bug!(callee_expr.span, "method without bare fn type");
tcx.mk_nil()
}
hir::ExprBreak(label, ref expr_opt) => {
- let loop_id = label.map(|l| l.loop_id);
let coerce_to = {
let mut enclosing_loops = self.enclosing_loops.borrow_mut();
- enclosing_loops.find_loop(loop_id).map(|ctxt| ctxt.coerce_to)
+ enclosing_loops.find_loop(label.loop_id).map(|ctxt| ctxt.coerce_to)
};
if let Some(coerce_to) = coerce_to {
let e_ty;
e_ty = tcx.mk_nil();
cause = self.misc(expr.span);
}
+
let mut enclosing_loops = self.enclosing_loops.borrow_mut();
- let ctxt = enclosing_loops.find_loop(loop_id).unwrap();
+ let ctxt = enclosing_loops.find_loop(label.loop_id).unwrap();
let result = if let Some(ref e) = *expr_opt {
// Special-case the first element, as it has no "previous expressions".
let container = self.tcx.associated_item(def_id).container;
match container {
ty::TraitContainer(trait_did) => {
- callee::check_legal_trait_for_method_call(self.ccx, span, trait_did)
+ callee::check_legal_trait_for_method_call(self.tcx, span, trait_did)
}
ty::ImplContainer(_) => {}
}
// errors if type parameters are provided in an inappropriate place.
let poly_segments = type_segment.is_some() as usize +
fn_segment.is_some() as usize;
- self.tcx.prohibit_type_params(&segments[..segments.len() - poly_segments]);
+ AstConv::prohibit_type_params(self, &segments[..segments.len() - poly_segments]);
match def {
Def::Local(def_id) | Def::Upvar(def_id, ..) => {
if let Some(ast_ty) = types.get(i) {
// A provided type parameter.
self.to_ty(ast_ty)
- } else if let (false, Some(default)) = (infer_types, def.default) {
+ } else if !infer_types && def.has_default {
// No type parameter provided, but a default exists.
+ let default = self.tcx.item_type(def.def_id);
default.subst_spanned(self.tcx, substs, Some(span))
} else {
// No type parameters were provided, we can infer all.
&generics.types
}
});
- let required_len = type_defs.iter()
- .take_while(|d| d.default.is_none())
- .count();
+ let required_len = type_defs.iter().take_while(|d| !d.has_default).count();
if types.len() > type_defs.len() {
let span = types[type_defs.len()].span;
let expected_text = count_type_params(type_defs.len());
}
}
-pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+pub fn check_bounds_are_used<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
generics: &hir::Generics,
ty: Ty<'tcx>) {
debug!("check_bounds_are_used(n_tps={}, ty={:?})",
for (&used, param) in tps_used.iter().zip(&generics.ty_params) {
if !used {
- struct_span_err!(ccx.tcx.sess, param.span, E0091,
+ struct_span_err!(tcx.sess, param.span, E0091,
"type parameter `{}` is unused",
param.name)
.span_label(param.span, &format!("unused type parameter"))
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::{self, PatKind};
-use self::SubjectNode::Subject;
-
// a variation on try that just returns unit
macro_rules! ignore_err {
($e:expr) => (match $e { Ok(e) => e, Err(_) => return () })
repeating_scope: ast::NodeId,
// id of AST node being analyzed (the subject of the analysis).
- subject: SubjectNode,
+ subject: ast::NodeId,
}
}
pub struct RepeatingScope(ast::NodeId);
-pub enum SubjectNode { Subject(ast::NodeId), None }
+pub struct Subject(ast::NodeId);
impl<'a, 'gcx, 'tcx> RegionCtxt<'a, 'gcx, 'tcx> {
pub fn new(fcx: &'a FnCtxt<'a, 'gcx, 'tcx>,
- initial_repeating_scope: RepeatingScope,
+ RepeatingScope(initial_repeating_scope): RepeatingScope,
initial_body_id: ast::NodeId,
- subject: SubjectNode) -> RegionCtxt<'a, 'gcx, 'tcx> {
- let RepeatingScope(initial_repeating_scope) = initial_repeating_scope;
+ Subject(subject): Subject) -> RegionCtxt<'a, 'gcx, 'tcx> {
RegionCtxt {
fcx: fcx,
repeating_scope: initial_repeating_scope,
}
fn resolve_regions_and_report_errors(&self) {
- let subject_node_id = match self.subject {
- Subject(s) => s,
- SubjectNode::None => {
- bug!("cannot resolve_regions_and_report_errors \
- without subject node");
- }
- };
+ let subject_node_id = self.subject;
self.fcx.resolve_regions_and_report_errors(&self.free_region_map,
subject_node_id);
// was applied on the base type, as that is always the case.
let fn_sig = method.ty.fn_sig();
let fn_sig = // late-bound regions should have been instantiated
- self.tcx.no_late_bound_regions(fn_sig).unwrap();
+ self.tcx.no_late_bound_regions(&fn_sig).unwrap();
let self_ty = fn_sig.inputs()[0];
let (m, r) = match self_ty.sty {
ty::TyRef(r, ref m) => (m.mutbl, r),
// If we are also inferred the closure kind here, update the
// main table and process any deferred resolutions.
- let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
if let Some(&kind) = self.temp_closure_kinds.get(&id) {
self.fcx.tables.borrow_mut().closure_kinds.insert(id, kind);
+ let closure_def_id = self.fcx.tcx.hir.local_def_id(id);
debug!("closure_kind({:?}) = {:?}", closure_def_id, kind);
let mut deferred_call_resolutions =
// except according to those terms.
use astconv::ExplicitSelf;
-use check::FnCtxt;
+use check::{Inherited, FnCtxt};
use constrained_type_params::{identify_constrained_type_params, Parameter};
-use CrateCtxt;
use hir::def_id::DefId;
use middle::region::{CodeExtent};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir;
-pub struct CheckTypeWellFormedVisitor<'ccx, 'tcx:'ccx> {
- ccx: &'ccx CrateCtxt<'ccx, 'tcx>,
+pub struct CheckTypeWellFormedVisitor<'a, 'tcx:'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
code: ObligationCauseCode<'tcx>,
}
let id = self.id;
let span = self.span;
self.inherited.enter(|inh| {
- let fcx = FnCtxt::new(&inh, Some(inh.ccx.tcx.types.never), id);
+ let fcx = FnCtxt::new(&inh, None, id);
let wf_tys = f(&fcx, &mut CheckTypeWellFormedVisitor {
- ccx: fcx.ccx,
+ tcx: fcx.tcx.global_tcx(),
code: code
});
fcx.select_all_obligations_or_error();
}
}
-impl<'ccx, 'gcx> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
- pub fn new(ccx: &'ccx CrateCtxt<'ccx, 'gcx>)
- -> CheckTypeWellFormedVisitor<'ccx, 'gcx> {
+impl<'a, 'gcx> CheckTypeWellFormedVisitor<'a, 'gcx> {
+ pub fn new(tcx: TyCtxt<'a, 'gcx, 'gcx>)
+ -> CheckTypeWellFormedVisitor<'a, 'gcx> {
CheckTypeWellFormedVisitor {
- ccx: ccx,
+ tcx: tcx,
code: ObligationCauseCode::MiscObligation
}
}
- fn tcx(&self) -> TyCtxt<'ccx, 'gcx, 'gcx> {
- self.ccx.tcx
- }
-
/// Checks that the field types (in a struct def'n) or argument types (in an enum def'n) are
/// well-formed, meaning that they do not require any constraints not declared in the struct
/// definition itself. For example, this definition would be illegal:
/// not included it frequently leads to confusing errors in fn bodies. So it's better to check
/// the types first.
fn check_item_well_formed(&mut self, item: &hir::Item) {
- let ccx = self.ccx;
+ let tcx = self.tcx;
debug!("check_item_well_formed(it.id={}, it.name={})",
item.id,
- ccx.tcx.item_path_str(ccx.tcx.hir.local_def_id(item.id)));
+ tcx.item_path_str(tcx.hir.local_def_id(item.id)));
match item.node {
/// Right now we check that every default trait implementation
hir::ItemImpl(_, hir::ImplPolarity::Negative, _, Some(_), ..) => {
// FIXME(#27579) what amount of WF checking do we need for neg impls?
- let trait_ref = ccx.tcx.impl_trait_ref(ccx.tcx.hir.local_def_id(item.id)).unwrap();
- if !ccx.tcx.trait_has_default_impl(trait_ref.def_id) {
- error_192(ccx, item.span);
+ let trait_ref = tcx.impl_trait_ref(tcx.hir.local_def_id(item.id)).unwrap();
+ if !tcx.trait_has_default_impl(trait_ref.def_id) {
+ error_192(tcx, item.span);
}
}
hir::ItemFn(.., body_id) => {
let method_ty = fcx.tcx.item_type(item.def_id);
let method_ty = fcx.instantiate_type_scheme(span, free_substs, &method_ty);
let predicates = fcx.instantiate_bounds(span, item.def_id, free_substs);
- let fty = match method_ty.sty {
- ty::TyFnDef(_, _, f) => f,
- _ => bug!()
- };
- this.check_fn_or_method(fcx, span, fty, &predicates,
+ let sig = method_ty.fn_sig();
+ this.check_fn_or_method(fcx, span, sig, &predicates,
free_id_outlive, &mut implied_bounds);
let sig_if_method = sig_if_method.expect("bad signature for method");
this.check_method_receiver(fcx, sig_if_method, &item,
}
fn for_item<'tcx>(&self, item: &hir::Item)
- -> CheckWfFcxBuilder<'ccx, 'gcx, 'tcx> {
+ -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
self.for_id(item.id, item.span)
}
fn for_id<'tcx>(&self, id: ast::NodeId, span: Span)
- -> CheckWfFcxBuilder<'ccx, 'gcx, 'tcx> {
+ -> CheckWfFcxBuilder<'a, 'gcx, 'tcx> {
CheckWfFcxBuilder {
- inherited: self.ccx.inherited(id),
+ inherited: Inherited::build(self.tcx, id),
code: self.code.clone(),
id: id,
span: span
//
// 3) that the trait definition does not have any type parameters
- let predicates = self.tcx().item_predicates(trait_def_id);
+ let predicates = self.tcx.item_predicates(trait_def_id);
// We must exclude the Self : Trait predicate contained by all
// traits.
}
});
- let has_ty_params = self.tcx().item_generics(trait_def_id).types.len() > 1;
+ let has_ty_params = self.tcx.item_generics(trait_def_id).types.len() > 1;
// We use an if-else here, since the generics will also trigger
// an extraneous error message when we find predicates like
// extraneous predicates created by things like
// an associated type inside the trait.
let mut err = None;
- if !self.tcx().associated_item_def_ids(trait_def_id).is_empty() {
- error_380(self.ccx, span);
+ if !self.tcx.associated_item_def_ids(trait_def_id).is_empty() {
+ error_380(self.tcx, span);
} else if has_ty_params {
- err = Some(struct_span_err!(self.tcx().sess, span, E0567,
+ err = Some(struct_span_err!(self.tcx.sess, span, E0567,
"traits with auto impls (`e.g. impl \
Trait for ..`) can not have type parameters"));
} else if has_predicates {
- err = Some(struct_span_err!(self.tcx().sess, span, E0568,
+ err = Some(struct_span_err!(self.tcx.sess, span, E0568,
"traits with auto impls (`e.g. impl \
Trait for ..`) cannot have predicates"));
}
}
fn check_trait(&mut self, item: &hir::Item) {
- let trait_def_id = self.tcx().hir.local_def_id(item.id);
+ let trait_def_id = self.tcx.hir.local_def_id(item.id);
- if self.tcx().trait_has_default_impl(trait_def_id) {
+ if self.tcx.trait_has_default_impl(trait_def_id) {
self.check_auto_trait(trait_def_id, item.span);
}
let def_id = fcx.tcx.hir.local_def_id(item.id);
let ty = fcx.tcx.item_type(def_id);
let item_ty = fcx.instantiate_type_scheme(item.span, free_substs, &ty);
- let bare_fn_ty = match item_ty.sty {
- ty::TyFnDef(.., ref bare_fn_ty) => bare_fn_ty,
- _ => {
- span_bug!(item.span, "Fn item without fn type");
- }
- };
+ let sig = item_ty.fn_sig();
let predicates = fcx.instantiate_bounds(item.span, def_id, free_substs);
let mut implied_bounds = vec![];
let free_id_outlive = fcx.tcx.region_maps.call_site_extent(item.id, body_id.node_id);
- this.check_fn_or_method(fcx, item.span, bare_fn_ty, &predicates,
+ this.check_fn_or_method(fcx, item.span, sig, &predicates,
free_id_outlive, &mut implied_bounds);
implied_bounds
})
fn check_fn_or_method<'fcx, 'tcx>(&mut self,
fcx: &FnCtxt<'fcx, 'gcx, 'tcx>,
span: Span,
- fty: &'tcx ty::BareFnTy<'tcx>,
+ sig: ty::PolyFnSig<'tcx>,
predicates: &ty::InstantiatedPredicates<'tcx>,
free_id_outlive: CodeExtent,
implied_bounds: &mut Vec<Ty<'tcx>>)
{
let free_substs = &fcx.parameter_environment.free_substs;
- let fty = fcx.instantiate_type_scheme(span, free_substs, &fty);
- let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &fty.sig);
+ let sig = fcx.instantiate_type_scheme(span, free_substs, &sig);
+ let sig = fcx.tcx.liberate_late_bound_regions(free_id_outlive, &sig);
for input_ty in sig.inputs() {
fcx.register_wf_obligation(&input_ty, span, self.code.clone());
item: &hir::Item,
ast_generics: &hir::Generics)
{
- let item_def_id = self.tcx().hir.local_def_id(item.id);
- let ty = self.tcx().item_type(item_def_id);
- if self.tcx().has_error_field(ty) {
+ let item_def_id = self.tcx.hir.local_def_id(item.id);
+ let ty = self.tcx.item_type(item_def_id);
+ if self.tcx.has_error_field(ty) {
return;
}
- let ty_predicates = self.tcx().item_predicates(item_def_id);
+ let ty_predicates = self.tcx.item_predicates(item_def_id);
assert_eq!(ty_predicates.parent, None);
- let variances = self.tcx().item_variances(item_def_id);
+ let variances = self.tcx.item_variances(item_def_id);
let mut constrained_parameters: FxHashSet<_> =
variances.iter().enumerate()
span: Span,
param_name: ast::Name)
{
- let mut err = error_392(self.ccx, span, param_name);
+ let mut err = error_392(self.tcx, span, param_name);
- let suggested_marker_id = self.tcx().lang_items.phantom_data();
+ let suggested_marker_id = self.tcx.lang_items.phantom_data();
match suggested_marker_id {
Some(def_id) => {
err.help(
&format!("consider removing `{}` or using a marker such as `{}`",
param_name,
- self.tcx().item_path_str(def_id)));
+ self.tcx.item_path_str(def_id)));
}
None => {
// no lang items, no help!
}
}
-impl<'ccx, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'ccx, 'tcx> {
+impl<'a, 'tcx, 'v> Visitor<'v> for CheckTypeWellFormedVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'v> {
NestedVisitorMap::None
}
}
}
-fn error_192(ccx: &CrateCtxt, span: Span) {
- span_err!(ccx.tcx.sess, span, E0192,
+fn error_192(tcx: TyCtxt, span: Span) {
+ span_err!(tcx.sess, span, E0192,
"negative impls are only allowed for traits with \
default impls (e.g., `Send` and `Sync`)")
}
-fn error_380(ccx: &CrateCtxt, span: Span) {
- span_err!(ccx.tcx.sess, span, E0380,
+fn error_380(tcx: TyCtxt, span: Span) {
+ span_err!(tcx.sess, span, E0380,
"traits with default impls (`e.g. impl \
Trait for ..`) must have no methods or associated items")
}
-fn error_392<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, span: Span, param_name: ast::Name)
+fn error_392<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, span: Span, param_name: ast::Name)
-> DiagnosticBuilder<'tcx> {
- let mut err = struct_span_err!(ccx.tcx.sess, span, E0392,
+ let mut err = struct_span_err!(tcx.sess, span, E0392,
"parameter `{}` is never used", param_name);
err.span_label(span, &format!("unused type parameter"));
err
use self::ResolveReason::*;
use check::FnCtxt;
-use hir::def_id::DefId;
use rustc::ty::{self, Ty, TyCtxt, MethodCall, MethodCallee};
use rustc::ty::adjustment;
use rustc::ty::fold::{TypeFolder,TypeFoldable};
use rustc::infer::{InferCtxt, FixupError};
use rustc::util::nodemap::{DefIdMap, DefIdSet};
-use std::cell::Cell;
use std::mem;
use syntax::ast;
// Entry point
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body) {
- assert_eq!(self.writeback_errors.get(), false);
-
+ pub fn resolve_type_vars_in_body(&self, body: &'gcx hir::Body)
+ -> &'gcx ty::TypeckTables<'gcx> {
let item_id = self.tcx.hir.body_owner(body.id());
let item_def_id = self.tcx.hir.local_def_id(item_id);
wbcx.visit_liberated_fn_sigs();
wbcx.visit_fru_field_types();
wbcx.visit_anon_types();
- wbcx.visit_deferred_obligations(item_id);
wbcx.visit_type_nodes();
wbcx.visit_cast_types();
wbcx.visit_lints();
- let tables = self.tcx.alloc_tables(wbcx.tables);
- self.tcx.tables.borrow_mut().insert(item_def_id, tables);
-
- let used_trait_imports = mem::replace(&mut *self.used_trait_imports.borrow_mut(),
+ let used_trait_imports = mem::replace(&mut self.tables.borrow_mut().used_trait_imports,
DefIdSet());
debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports);
- self.tcx.used_trait_imports.borrow_mut().insert(item_def_id, used_trait_imports);
+ wbcx.tables.used_trait_imports = used_trait_imports;
+
+ wbcx.tables.tainted_by_errors = self.is_tainted_by_errors();
+
+ self.tcx.alloc_tables(wbcx.tables)
}
}
}
fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
- if self.fcx.writeback_errors.get() {
- return;
- }
-
self.visit_node_id(ResolvingExpr(s.span), s.node.id());
intravisit::walk_stmt(self, s);
}
fn visit_expr(&mut self, e: &'gcx hir::Expr) {
- if self.fcx.writeback_errors.get() {
- return;
- }
-
self.fix_scalar_builtin_expr(e);
self.visit_node_id(ResolvingExpr(e.span), e.id);
}
fn visit_block(&mut self, b: &'gcx hir::Block) {
- if self.fcx.writeback_errors.get() {
- return;
- }
-
self.visit_node_id(ResolvingExpr(b.span), b.id);
intravisit::walk_block(self, b);
}
fn visit_pat(&mut self, p: &'gcx hir::Pat) {
- if self.fcx.writeback_errors.get() {
- return;
- }
-
self.visit_node_id(ResolvingPattern(p.span), p.id);
-
intravisit::walk_pat(self, p);
}
fn visit_local(&mut self, l: &'gcx hir::Local) {
- if self.fcx.writeback_errors.get() {
- return;
- }
-
let var_ty = self.fcx.local_ty(l.span, l.id);
let var_ty = self.resolve(&var_ty, ResolvingLocal(l.span));
self.write_ty_to_tables(l.id, var_ty);
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
fn visit_upvar_borrow_map(&mut self) {
- if self.fcx.writeback_errors.get() {
- return;
- }
-
for (upvar_id, upvar_capture) in self.fcx.tables.borrow().upvar_capture_map.iter() {
let new_upvar_capture = match *upvar_capture {
ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue,
}
}
- fn visit_closures(&self) {
- if self.fcx.writeback_errors.get() {
- return
- }
-
+ fn visit_closures(&mut self) {
for (&id, closure_ty) in self.fcx.tables.borrow().closure_tys.iter() {
let closure_ty = self.resolve(closure_ty, ResolvingClosure(id));
- let def_id = self.tcx().hir.local_def_id(id);
- self.tcx().closure_tys.borrow_mut().insert(def_id, closure_ty);
+ self.tables.closure_tys.insert(id, closure_ty);
}
for (&id, &closure_kind) in self.fcx.tables.borrow().closure_kinds.iter() {
- let def_id = self.tcx().hir.local_def_id(id);
- self.tcx().closure_kinds.borrow_mut().insert(def_id, closure_kind);
+ self.tables.closure_kinds.insert(id, closure_kind);
}
}
fn visit_cast_types(&mut self) {
- if self.fcx.writeback_errors.get() {
- return
- }
-
self.tables.cast_kinds.extend(
self.fcx.tables.borrow().cast_kinds.iter().map(|(&key, &value)| (key, value)));
}
fn visit_lints(&mut self) {
- if self.fcx.writeback_errors.get() {
- return
- }
-
self.fcx.tables.borrow_mut().lints.transfer(&mut self.tables.lints);
}
- fn visit_anon_types(&self) {
- if self.fcx.writeback_errors.get() {
- return
- }
-
+ fn visit_anon_types(&mut self) {
let gcx = self.tcx().global_tcx();
- for (&def_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
- let reason = ResolvingAnonTy(def_id);
+ for (&node_id, &concrete_ty) in self.fcx.anon_types.borrow().iter() {
+ let reason = ResolvingAnonTy(node_id);
let inside_ty = self.resolve(&concrete_ty, reason);
// Convert the type from the function into a type valid outside
}
});
- gcx.item_types.borrow_mut().insert(def_id, outside_ty);
+ self.tables.node_types.insert(node_id, outside_ty);
}
}
adjustment::Adjust::MutToConstPointer
}
+ adjustment::Adjust::ClosureFnPointer => {
+ adjustment::Adjust::ClosureFnPointer
+ }
+
adjustment::Adjust::UnsafeFnPointer => {
adjustment::Adjust::UnsafeFnPointer
}
}
}
- fn visit_deferred_obligations(&mut self, item_id: ast::NodeId) {
- let deferred_obligations = self.fcx.deferred_obligations.borrow();
- let obligations: Vec<_> = deferred_obligations.iter().map(|obligation| {
- let reason = ResolvingDeferredObligation(obligation.cause.span);
- self.resolve(obligation, reason)
- }).collect();
-
- if !obligations.is_empty() {
- assert!(self.fcx.ccx.deferred_obligations.borrow_mut()
- .insert(item_id, obligations).is_none());
- }
- }
-
fn visit_type_nodes(&self) {
for (&id, ty) in self.fcx.ast_ty_to_ty_cache.borrow().iter() {
let ty = self.resolve(ty, ResolvingTyNode(id));
- self.fcx.ccx.ast_ty_to_ty_cache.borrow_mut().insert(id, ty);
+ self.fcx.tcx.ast_ty_to_ty_cache.borrow_mut().insert(id, ty);
}
}
ResolvingClosure(ast::NodeId),
ResolvingFnSig(ast::NodeId),
ResolvingFieldTypes(ast::NodeId),
- ResolvingAnonTy(DefId),
- ResolvingDeferredObligation(Span),
+ ResolvingAnonTy(ast::NodeId),
ResolvingTyNode(ast::NodeId),
}
ResolvingClosure(id) |
ResolvingFnSig(id) |
ResolvingFieldTypes(id) |
- ResolvingTyNode(id) => {
+ ResolvingTyNode(id) |
+ ResolvingAnonTy(id) => {
tcx.hir.span(id)
}
- ResolvingAnonTy(did) => {
- tcx.def_span(did)
- }
- ResolvingDeferredObligation(span) => span
}
}
}
struct Resolver<'cx, 'gcx: 'cx+'tcx, 'tcx: 'cx> {
tcx: TyCtxt<'cx, 'gcx, 'tcx>,
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
- writeback_errors: &'cx Cell<bool>,
reason: ResolveReason,
}
reason: ResolveReason)
-> Resolver<'cx, 'gcx, 'tcx>
{
- Resolver::from_infcx(fcx, &fcx.writeback_errors, reason)
+ Resolver::from_infcx(fcx, reason)
}
fn from_infcx(infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
- writeback_errors: &'cx Cell<bool>,
reason: ResolveReason)
-> Resolver<'cx, 'gcx, 'tcx>
{
Resolver { infcx: infcx,
tcx: infcx.tcx,
- writeback_errors: writeback_errors,
reason: reason }
}
fn report_error(&self, e: FixupError) {
- self.writeback_errors.set(true);
if !self.tcx.sess.has_errors() {
match self.reason {
ResolvingExpr(span) => {
ResolvingFnSig(_) |
ResolvingFieldTypes(_) |
- ResolvingDeferredObligation(_) |
ResolvingTyNode(_) => {
// any failures here should also fail when
// resolving the patterns, closure types, or
let item_def_id = tcx.hir.local_def_id(item_id);
// this will have been written by the main typeck pass
- if let Some(imports) = tcx.used_trait_imports.borrow().get(&item_def_id) {
+ if let Some(tables) = tcx.maps.typeck_tables.borrow().get(&item_def_id) {
+ let imports = &tables.used_trait_imports;
debug!("GatherVisitor: item_def_id={:?} with imports {:#?}", item_def_id, imports);
used_trait_imports.extend(imports);
} else {
use rustc::hir::map as hir_map;
use rustc::hir::{self, ItemImpl};
-pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- check_trait(tcx, tcx.lang_items.drop_trait(), visit_implementation_of_drop);
- check_trait(tcx, tcx.lang_items.copy_trait(), visit_implementation_of_copy);
- check_trait(
- tcx,
- tcx.lang_items.coerce_unsized_trait(),
- visit_implementation_of_coerce_unsized);
+pub fn check_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_def_id: DefId) {
+ Checker { tcx, trait_def_id }
+ .check(tcx.lang_items.drop_trait(), visit_implementation_of_drop)
+ .check(tcx.lang_items.copy_trait(), visit_implementation_of_copy)
+ .check(tcx.lang_items.coerce_unsized_trait(),
+ visit_implementation_of_coerce_unsized);
}
-fn check_trait<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- trait_def_id: Option<DefId>,
- mut f: F)
- where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
-{
- if let Some(trait_def_id) = trait_def_id {
- let mut impls = vec![];
- tcx.lookup_trait_def(trait_def_id).for_each_impl(tcx, |did| {
- impls.push(did);
- });
- impls.sort();
- for impl_def_id in impls {
- f(tcx, trait_def_id, impl_def_id);
+struct Checker<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ trait_def_id: DefId
+}
+
+impl<'a, 'tcx> Checker<'a, 'tcx> {
+ fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> &Self
+ where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
+ {
+ if Some(self.trait_def_id) == trait_def_id {
+ for &impl_id in self.tcx.hir.trait_impls(self.trait_def_id) {
+ let impl_def_id = self.tcx.hir.local_def_id(impl_id);
+ f(self.tcx, self.trait_def_id, impl_def_id);
+ }
}
+ self
}
}
fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
_drop_did: DefId,
impl_did: DefId) {
- let items = tcx.associated_item_def_ids(impl_did);
- if items.is_empty() {
- // We'll error out later. For now, just don't ICE.
- return;
- }
- let method_def_id = items[0];
-
- let self_type = tcx.item_type(impl_did);
- match self_type.sty {
- ty::TyAdt(type_def, _) => {
- type_def.set_destructor(method_def_id);
- }
+ match tcx.item_type(impl_did).sty {
+ ty::TyAdt(..) => {}
_ => {
// Destructors only work on nominal types.
if let Some(impl_node_id) = tcx.hir.as_local_node_id(impl_did) {
source,
target);
- tcx.infer_ctxt(param_env, Reveal::ExactMatch).enter(|infcx| {
+ tcx.infer_ctxt(param_env, Reveal::UserFacing).enter(|infcx| {
let cause = ObligationCause::misc(span, impl_node_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
mt_b: ty::TypeAndMut<'tcx>,
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
if let Some(kind) = kind {
- tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
+ tcx.maps.custom_coerce_unsized_kind.borrow_mut().insert(impl_did, kind);
}
});
}
--- /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 rustc::dep_graph::DepNode;
+use rustc::hir::def_id::DefId;
+use rustc::hir;
+use rustc::hir::itemlikevisit::ItemLikeVisitor;
+use rustc::lint;
+use rustc::traits::{self, Reveal};
+use rustc::ty::{self, TyCtxt};
+
+use syntax::ast;
+use syntax_pos::Span;
+
+struct InherentCollect<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentCollect<'a, 'tcx> {
+ fn visit_item(&mut self, item: &hir::Item) {
+ let (unsafety, ty) = match item.node {
+ hir::ItemImpl(unsafety, .., None, ref ty, _) => (unsafety, ty),
+ _ => return
+ };
+
+ match unsafety {
+ hir::Unsafety::Normal => {
+ // OK
+ }
+ hir::Unsafety::Unsafe => {
+ span_err!(self.tcx.sess,
+ item.span,
+ E0197,
+ "inherent impls cannot be declared as unsafe");
+ }
+ }
+
+ let def_id = self.tcx.hir.local_def_id(item.id);
+ let self_ty = self.tcx.item_type(def_id);
+ match self_ty.sty {
+ ty::TyAdt(def, _) => {
+ self.check_def_id(item, def.did);
+ }
+ ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
+ self.check_def_id(item, data.principal().unwrap().def_id());
+ }
+ ty::TyChar => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.char_impl(),
+ "char",
+ "char",
+ item.span);
+ }
+ ty::TyStr => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.str_impl(),
+ "str",
+ "str",
+ item.span);
+ }
+ ty::TySlice(_) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.slice_impl(),
+ "slice",
+ "[T]",
+ item.span);
+ }
+ ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.const_ptr_impl(),
+ "const_ptr",
+ "*const T",
+ item.span);
+ }
+ ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.mut_ptr_impl(),
+ "mut_ptr",
+ "*mut T",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I8) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i8_impl(),
+ "i8",
+ "i8",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I16) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i16_impl(),
+ "i16",
+ "i16",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I32) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i32_impl(),
+ "i32",
+ "i32",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I64) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i64_impl(),
+ "i64",
+ "i64",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::I128) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.i128_impl(),
+ "i128",
+ "i128",
+ item.span);
+ }
+ ty::TyInt(ast::IntTy::Is) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.isize_impl(),
+ "isize",
+ "isize",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U8) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u8_impl(),
+ "u8",
+ "u8",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U16) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u16_impl(),
+ "u16",
+ "u16",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U32) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u32_impl(),
+ "u32",
+ "u32",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U64) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u64_impl(),
+ "u64",
+ "u64",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::U128) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.u128_impl(),
+ "u128",
+ "u128",
+ item.span);
+ }
+ ty::TyUint(ast::UintTy::Us) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.usize_impl(),
+ "usize",
+ "usize",
+ item.span);
+ }
+ ty::TyFloat(ast::FloatTy::F32) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.f32_impl(),
+ "f32",
+ "f32",
+ item.span);
+ }
+ ty::TyFloat(ast::FloatTy::F64) => {
+ self.check_primitive_impl(def_id,
+ self.tcx.lang_items.f64_impl(),
+ "f64",
+ "f64",
+ item.span);
+ }
+ ty::TyError => {
+ return;
+ }
+ _ => {
+ struct_span_err!(self.tcx.sess,
+ ty.span,
+ E0118,
+ "no base type found for inherent implementation")
+ .span_label(ty.span, &format!("impl requires a base type"))
+ .note(&format!("either implement a trait on it or create a newtype \
+ to wrap it instead"))
+ .emit();
+ return;
+ }
+ }
+ }
+
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
+ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+ }
+}
+
+impl<'a, 'tcx> InherentCollect<'a, 'tcx> {
+ fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
+ if def_id.is_local() {
+ // Add the implementation to the mapping from implementation to base
+ // type def ID, if there is a base type for this implementation and
+ // the implementation does not have any associated traits.
+ let impl_def_id = self.tcx.hir.local_def_id(item.id);
+
+ // Subtle: it'd be better to collect these into a local map
+ // and then write the vector only once all items are known,
+ // but that leads to degenerate dep-graphs. The problem is
+ // that the write of that big vector winds up having reads
+ // from *all* impls in the krate, since we've lost the
+ // precision basically. This would be ok in the firewall
+ // model so once we've made progess towards that we can modify
+ // the strategy here. In the meantime, using `push` is ok
+ // because we are doing this as a pre-pass before anyone
+ // actually reads from `inherent_impls` -- and we know this is
+ // true beacuse we hold the refcell lock.
+ self.tcx.maps.inherent_impls.borrow_mut().push(def_id, impl_def_id);
+ } else {
+ struct_span_err!(self.tcx.sess,
+ item.span,
+ E0116,
+ "cannot define inherent `impl` for a type outside of the crate \
+ where the type is defined")
+ .span_label(item.span,
+ &format!("impl for type defined outside of crate."))
+ .note("define and implement a trait or new type instead")
+ .emit();
+ }
+ }
+
+ fn check_primitive_impl(&self,
+ impl_def_id: DefId,
+ lang_def_id: Option<DefId>,
+ lang: &str,
+ ty: &str,
+ span: Span) {
+ match lang_def_id {
+ Some(lang_def_id) if lang_def_id == impl_def_id => {
+ // OK
+ }
+ _ => {
+ struct_span_err!(self.tcx.sess,
+ span,
+ E0390,
+ "only a single inherent implementation marked with `#[lang = \
+ \"{}\"]` is allowed for the `{}` primitive",
+ lang,
+ ty)
+ .span_help(span, "consider using a trait to implement these methods")
+ .emit();
+ }
+ }
+ }
+}
+
+struct InherentOverlapChecker<'a, 'tcx: 'a> {
+ tcx: TyCtxt<'a, 'tcx, 'tcx>
+}
+
+impl<'a, 'tcx> InherentOverlapChecker<'a, 'tcx> {
+ fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
+ #[derive(Copy, Clone, PartialEq)]
+ enum Namespace {
+ Type,
+ Value,
+ }
+
+ let name_and_namespace = |def_id| {
+ let item = self.tcx.associated_item(def_id);
+ (item.name, match item.kind {
+ ty::AssociatedKind::Type => Namespace::Type,
+ ty::AssociatedKind::Const |
+ ty::AssociatedKind::Method => Namespace::Value,
+ })
+ };
+
+ let impl_items1 = self.tcx.associated_item_def_ids(impl1);
+ let impl_items2 = self.tcx.associated_item_def_ids(impl2);
+
+ for &item1 in &impl_items1[..] {
+ let (name, namespace) = name_and_namespace(item1);
+
+ for &item2 in &impl_items2[..] {
+ if (name, namespace) == name_and_namespace(item2) {
+ let msg = format!("duplicate definitions with name `{}`", name);
+ let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
+ self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
+ node_id,
+ self.tcx.span_of_impl(item1).unwrap(),
+ msg);
+ }
+ }
+ }
+ }
+
+ fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
+ let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
+
+ let inherent_impls = self.tcx.maps.inherent_impls.borrow();
+ let impls = match inherent_impls.get(&ty_def_id) {
+ Some(impls) => impls,
+ None => return,
+ };
+
+ for (i, &impl1_def_id) in impls.iter().enumerate() {
+ for &impl2_def_id in &impls[(i + 1)..] {
+ self.tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
+ if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
+ self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
+ }
+ });
+ }
+ }
+ }
+}
+
+impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for InherentOverlapChecker<'a, 'tcx> {
+ fn visit_item(&mut self, item: &'v hir::Item) {
+ match item.node {
+ hir::ItemEnum(..) |
+ hir::ItemStruct(..) |
+ hir::ItemTrait(..) |
+ hir::ItemUnion(..) => {
+ let type_def_id = self.tcx.hir.local_def_id(item.id);
+ self.check_for_overlapping_inherent_impls(type_def_id);
+ }
+ _ => {}
+ }
+ }
+
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
+ fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
+ }
+}
+
+pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl,
+ &mut InherentCollect { tcx });
+ tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial,
+ &mut InherentOverlapChecker { tcx });
+}
// done by the orphan and overlap modules. Then we build up various
// mappings. That mapping code resides here.
-use dep_graph::DepTrackingMap;
-use hir::def_id::DefId;
-use rustc::ty::{self, maps, TyCtxt, TypeFoldable};
-use rustc::ty::{Ty, TyBool, TyChar, TyError};
-use rustc::ty::{TyParam, TyRawPtr};
-use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
-use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
-use rustc::ty::{TyUint, TyClosure, TyFnDef, TyFnPtr};
-use rustc::ty::{TyProjection, TyAnon};
-use CrateCtxt;
-use syntax_pos::Span;
+use hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
+use rustc::ty::{self, TyCtxt, TypeFoldable};
+use rustc::ty::maps::Providers;
use rustc::dep_graph::DepNode;
-use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use rustc::hir::{Item, ItemImpl};
-use rustc::hir;
-use std::cell::RefMut;
+
+use syntax::ast;
+use syntax_pos::DUMMY_SP;
mod builtin;
+mod inherent;
mod orphan;
mod overlap;
mod unsafety;
-struct CoherenceCollect<'a, 'tcx: 'a> {
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- inherent_impls: RefMut<'a, DepTrackingMap<maps::InherentImpls<'tcx>>>,
-}
-
-impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCollect<'a, 'tcx> {
- fn visit_item(&mut self, item: &Item) {
- if let ItemImpl(..) = item.node {
- self.check_implementation(item)
- }
- }
-
- fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
- }
+fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
+ let impl_def_id = tcx.hir.local_def_id(node_id);
- fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
- }
-}
+ // If there are no traits, then this implementation must have a
+ // base type.
-impl<'a, 'tcx> CoherenceCollect<'a, 'tcx> {
- fn check(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- let inherent_impls = tcx.inherent_impls.borrow_mut();
- let mut this = &mut CoherenceCollect { tcx, inherent_impls };
+ if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) {
+ debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
+ trait_ref,
+ tcx.item_path_str(impl_def_id));
- // Check implementations and traits. This populates the tables
- // containing the inherent methods and extension methods. It also
- // builds up the trait inheritance table.
- tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, this);
- }
-
- // Returns the def ID of the base type, if there is one.
- fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
- match ty.sty {
- TyAdt(def, _) => Some(def.did),
-
- TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
-
- TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
- TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
- TyNever | TyRawPtr(_) | TyRef(..) | TyProjection(..) => None,
-
- TyInfer(..) | TyClosure(..) | TyAnon(..) => {
- // `ty` comes from a user declaration so we should only expect types
- // that the user can type
- span_bug!(span,
- "coherence encountered unexpected type searching for base type: {}",
- ty);
- }
+ // Skip impls where one of the self type is an error type.
+ // This occurs with e.g. resolve failures (#30589).
+ if trait_ref.references_error() {
+ return;
}
- }
- fn check_implementation(&mut self, item: &Item) {
- let tcx = self.tcx;
- let impl_did = tcx.hir.local_def_id(item.id);
- let self_type = tcx.item_type(impl_did);
-
- // If there are no traits, then this implementation must have a
- // base type.
-
- if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
- debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
- trait_ref,
- item.name);
-
- // Skip impls where one of the self type is an error type.
- // This occurs with e.g. resolve failures (#30589).
- if trait_ref.references_error() {
- return;
- }
-
- enforce_trait_manually_implementable(self.tcx, item.span, trait_ref.def_id);
- self.add_trait_impl(trait_ref, impl_did);
- } else {
- // Skip inherent impls where the self type is an error
- // type. This occurs with e.g. resolve failures (#30589).
- if self_type.references_error() {
- return;
- }
-
- // Add the implementation to the mapping from implementation to base
- // type def ID, if there is a base type for this implementation and
- // the implementation does not have any associated traits.
- if let Some(base_def_id) = self.get_base_type_def_id(item.span, self_type) {
- self.add_inherent_impl(base_def_id, impl_did);
- }
- }
+ enforce_trait_manually_implementable(tcx, impl_def_id, trait_ref.def_id);
+ let trait_def = tcx.lookup_trait_def(trait_ref.def_id);
+ trait_def.record_local_impl(tcx, impl_def_id, trait_ref);
}
+}
- fn add_inherent_impl(&mut self, base_def_id: DefId, impl_def_id: DefId) {
- // Subtle: it'd be better to collect these into a local map
- // and then write the vector only once all items are known,
- // but that leads to degenerate dep-graphs. The problem is
- // that the write of that big vector winds up having reads
- // from *all* impls in the krate, since we've lost the
- // precision basically. This would be ok in the firewall
- // model so once we've made progess towards that we can modify
- // the strategy here. In the meantime, using `push` is ok
- // because we are doing this as a pre-pass before anyone
- // actually reads from `inherent_impls` -- and we know this is
- // true beacuse we hold the refcell lock.
- self.inherent_impls.push(base_def_id, impl_def_id);
+fn enforce_trait_manually_implementable(tcx: TyCtxt, impl_def_id: DefId, trait_def_id: DefId) {
+ let did = Some(trait_def_id);
+ let li = &tcx.lang_items;
+
+ // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
+ if did == li.sized_trait() {
+ let span = tcx.span_of_impl(impl_def_id).unwrap();
+ struct_span_err!(tcx.sess,
+ span,
+ E0322,
+ "explicit impls for the `Sized` trait are not permitted")
+ .span_label(span, &format!("impl of 'Sized' not allowed"))
+ .emit();
+ return;
}
- fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
- debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
- impl_trait_ref,
- impl_def_id);
- let trait_def = self.tcx.lookup_trait_def(impl_trait_ref.def_id);
- trait_def.record_local_impl(self.tcx, impl_def_id, impl_trait_ref);
+ if did == li.unsize_trait() {
+ let span = tcx.span_of_impl(impl_def_id).unwrap();
+ span_err!(tcx.sess,
+ span,
+ E0328,
+ "explicit impls for the `Unsize` trait are not permitted");
+ return;
}
-}
-fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: DefId) {
if tcx.sess.features.borrow().unboxed_closures {
- // the feature gate allows all of them
+ // the feature gate allows all Fn traits
return;
}
- let did = Some(trait_def_id);
- let li = &tcx.lang_items;
let trait_name = if did == li.fn_trait() {
"Fn"
return; // everything OK
};
let mut err = struct_span_err!(tcx.sess,
- sp,
+ tcx.span_of_impl(impl_def_id).unwrap(),
E0183,
"manual implementations of `{}` are experimental",
trait_name);
err.emit();
}
-pub fn check_coherence(ccx: &CrateCtxt) {
- CoherenceCollect::check(ccx.tcx);
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ coherent_trait,
+ coherent_inherent_impls,
+ ..*providers
+ };
+}
+
+fn coherent_trait<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ (_, def_id): (CrateNum, DefId)) {
+ tcx.populate_implementations_for_trait_if_necessary(def_id);
+
+ let impls = tcx.hir.trait_impls(def_id);
+ for &impl_id in impls {
+ check_impl(tcx, impl_id);
+ }
+ for &impl_id in impls {
+ overlap::check_impl(tcx, impl_id);
+ }
+ builtin::check_trait(tcx, def_id);
+}
+
+fn coherent_inherent_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, _: CrateNum) {
+ inherent::check(tcx);
+}
+
+pub fn check_coherence<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ let _task = tcx.dep_graph.in_task(DepNode::Coherence);
+ for &trait_def_id in tcx.hir.krate().trait_impls.keys() {
+ ty::queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, trait_def_id));
+ }
+
+ unsafety::check(tcx);
+ orphan::check(tcx);
+ overlap::check_default_impls(tcx);
- let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
- unsafety::check(ccx.tcx);
- orphan::check(ccx.tcx);
- overlap::check(ccx.tcx);
- builtin::check(ccx.tcx);
+ ty::queries::coherent_inherent_impls::get(tcx, DUMMY_SP, LOCAL_CRATE);
}
//! Orphan checker: every impl either implements a trait defined in this
//! crate or pertains to a type defined in this crate.
-use hir::def_id::{DefId, LOCAL_CRATE};
use rustc::traits;
use rustc::ty::{self, TyCtxt};
-use syntax::ast;
-use syntax_pos::Span;
use rustc::dep_graph::DepNode;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir;
tcx: TyCtxt<'cx, 'tcx, 'tcx>,
}
-impl<'cx, 'tcx> OrphanChecker<'cx, 'tcx> {
- fn check_def_id(&self, item: &hir::Item, def_id: DefId) {
- if def_id.krate != LOCAL_CRATE {
- struct_span_err!(self.tcx.sess,
- item.span,
- E0116,
- "cannot define inherent `impl` for a type outside of the crate \
- where the type is defined")
- .span_label(item.span,
- &format!("impl for type defined outside of crate."))
- .note("define and implement a trait or new type instead")
- .emit();
- }
- }
-
- fn check_primitive_impl(&self,
- impl_def_id: DefId,
- lang_def_id: Option<DefId>,
- lang: &str,
- ty: &str,
- span: Span) {
- match lang_def_id {
- Some(lang_def_id) if lang_def_id == impl_def_id => {
- // OK
- }
- _ => {
- struct_span_err!(self.tcx.sess,
- span,
- E0390,
- "only a single inherent implementation marked with `#[lang = \
- \"{}\"]` is allowed for the `{}` primitive",
- lang,
- ty)
- .span_help(span, "consider using a trait to implement these methods")
- .emit();
- }
- }
- }
-}
-
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
/// Checks exactly one impl for orphan rules and other such
/// restrictions. In this fn, it can happen that multiple errors
fn visit_item(&mut self, item: &hir::Item) {
let def_id = self.tcx.hir.local_def_id(item.id);
match item.node {
- hir::ItemImpl(.., None, ref ty, _) => {
- // For inherent impls, self type must be a nominal type
- // defined in this crate.
- debug!("coherence2::orphan check: inherent impl {}",
- self.tcx.hir.node_to_string(item.id));
- let self_ty = self.tcx.item_type(def_id);
- match self_ty.sty {
- ty::TyAdt(def, _) => {
- self.check_def_id(item, def.did);
- }
- ty::TyDynamic(ref data, ..) if data.principal().is_some() => {
- self.check_def_id(item, data.principal().unwrap().def_id());
- }
- ty::TyChar => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.char_impl(),
- "char",
- "char",
- item.span);
- }
- ty::TyStr => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.str_impl(),
- "str",
- "str",
- item.span);
- }
- ty::TySlice(_) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.slice_impl(),
- "slice",
- "[T]",
- item.span);
- }
- ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.const_ptr_impl(),
- "const_ptr",
- "*const T",
- item.span);
- }
- ty::TyRawPtr(ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.mut_ptr_impl(),
- "mut_ptr",
- "*mut T",
- item.span);
- }
- ty::TyInt(ast::IntTy::I8) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i8_impl(),
- "i8",
- "i8",
- item.span);
- }
- ty::TyInt(ast::IntTy::I16) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i16_impl(),
- "i16",
- "i16",
- item.span);
- }
- ty::TyInt(ast::IntTy::I32) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i32_impl(),
- "i32",
- "i32",
- item.span);
- }
- ty::TyInt(ast::IntTy::I64) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i64_impl(),
- "i64",
- "i64",
- item.span);
- }
- ty::TyInt(ast::IntTy::I128) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.i128_impl(),
- "i128",
- "i128",
- item.span);
- }
- ty::TyInt(ast::IntTy::Is) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.isize_impl(),
- "isize",
- "isize",
- item.span);
- }
- ty::TyUint(ast::UintTy::U8) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u8_impl(),
- "u8",
- "u8",
- item.span);
- }
- ty::TyUint(ast::UintTy::U16) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u16_impl(),
- "u16",
- "u16",
- item.span);
- }
- ty::TyUint(ast::UintTy::U32) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u32_impl(),
- "u32",
- "u32",
- item.span);
- }
- ty::TyUint(ast::UintTy::U64) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u64_impl(),
- "u64",
- "u64",
- item.span);
- }
- ty::TyUint(ast::UintTy::U128) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.u128_impl(),
- "u128",
- "u128",
- item.span);
- }
- ty::TyUint(ast::UintTy::Us) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.usize_impl(),
- "usize",
- "usize",
- item.span);
- }
- ty::TyFloat(ast::FloatTy::F32) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.f32_impl(),
- "f32",
- "f32",
- item.span);
- }
- ty::TyFloat(ast::FloatTy::F64) => {
- self.check_primitive_impl(def_id,
- self.tcx.lang_items.f64_impl(),
- "f64",
- "f64",
- item.span);
- }
- ty::TyError => {
- return;
- }
- _ => {
- struct_span_err!(self.tcx.sess,
- ty.span,
- E0118,
- "no base type found for inherent implementation")
- .span_label(ty.span, &format!("impl requires a base type"))
- .note(&format!("either implement a trait on it or create a newtype \
- to wrap it instead"))
- .emit();
- return;
- }
- }
- }
hir::ItemImpl(.., Some(_), _, _) => {
// "Trait" impl
debug!("coherence2::orphan check: trait impl {}",
trait_def_id,
self.tcx.trait_has_default_impl(trait_def_id));
if self.tcx.trait_has_default_impl(trait_def_id) &&
- trait_def_id.krate != LOCAL_CRATE {
+ !trait_def_id.is_local() {
let self_ty = trait_ref.self_ty();
let opt_self_def_id = match self_ty.sty {
ty::TyAdt(self_def, _) => Some(self_def.did),
return;
}
}
-
- // Disallow *all* explicit impls of `Sized` and `Unsize` for now.
- if Some(trait_def_id) == self.tcx.lang_items.sized_trait() {
- struct_span_err!(self.tcx.sess,
- item.span,
- E0322,
- "explicit impls for the `Sized` trait are not permitted")
- .span_label(item.span, &format!("impl of 'Sized' not allowed"))
- .emit();
- return;
- }
- if Some(trait_def_id) == self.tcx.lang_items.unsize_trait() {
- span_err!(self.tcx.sess,
- item.span,
- E0328,
- "explicit impls for the `Unsize` trait are not permitted");
- return;
- }
}
hir::ItemDefaultImpl(_, ref item_trait_ref) => {
// "Trait" impl
debug!("coherence2::orphan check: default trait impl {}",
self.tcx.hir.node_to_string(item.id));
let trait_ref = self.tcx.impl_trait_ref(def_id).unwrap();
- if trait_ref.def_id.krate != LOCAL_CRATE {
+ if !trait_ref.def_id.is_local() {
struct_span_err!(self.tcx.sess,
item_trait_ref.path.span,
E0318,
//! same type. Likewise, no two inherent impls for a given type
//! constructor provide a method with the same name.
-use hir::def_id::DefId;
-use rustc::traits::{self, Reveal};
+use rustc::traits;
use rustc::ty::{self, TyCtxt, TypeFoldable};
use syntax::ast;
use rustc::dep_graph::DepNode;
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
-use util::nodemap::DefIdMap;
-use lint;
-pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
- let mut overlap = OverlapChecker {
- tcx: tcx,
- default_impls: DefIdMap(),
- };
+pub fn check_default_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ let mut overlap = OverlapChecker { tcx };
// this secondary walk specifically checks for some other cases,
// like defaulted traits, for which additional overlap rules exist
tcx.visit_all_item_likes_in_krate(DepNode::CoherenceOverlapCheckSpecial, &mut overlap);
}
-struct OverlapChecker<'cx, 'tcx: 'cx> {
- tcx: TyCtxt<'cx, 'tcx, 'tcx>,
-
- // maps from a trait def-id to an impl id
- default_impls: DefIdMap<ast::NodeId>,
-}
+pub fn check_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, node_id: ast::NodeId) {
+ let impl_def_id = tcx.hir.local_def_id(node_id);
+ let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap();
+ let trait_def_id = trait_ref.def_id;
-impl<'cx, 'tcx> OverlapChecker<'cx, 'tcx> {
- fn check_for_common_items_in_impls(&self, impl1: DefId, impl2: DefId) {
- #[derive(Copy, Clone, PartialEq)]
- enum Namespace {
- Type,
- Value,
- }
+ if trait_ref.references_error() {
+ debug!("coherence: skipping impl {:?} with error {:?}",
+ impl_def_id, trait_ref);
+ return
+ }
- let name_and_namespace = |def_id| {
- let item = self.tcx.associated_item(def_id);
- (item.name, match item.kind {
- ty::AssociatedKind::Type => Namespace::Type,
- ty::AssociatedKind::Const |
- ty::AssociatedKind::Method => Namespace::Value,
- })
- };
-
- let impl_items1 = self.tcx.associated_item_def_ids(impl1);
- let impl_items2 = self.tcx.associated_item_def_ids(impl2);
-
- for &item1 in &impl_items1[..] {
- let (name, namespace) = name_and_namespace(item1);
-
- for &item2 in &impl_items2[..] {
- if (name, namespace) == name_and_namespace(item2) {
- let msg = format!("duplicate definitions with name `{}`", name);
- let node_id = self.tcx.hir.as_local_node_id(item1).unwrap();
- self.tcx.sess.add_lint(lint::builtin::OVERLAPPING_INHERENT_IMPLS,
- node_id,
- self.tcx.span_of_impl(item1).unwrap(),
- msg);
- }
+ let _task =
+ tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
+
+ let def = tcx.lookup_trait_def(trait_def_id);
+
+ // attempt to insert into the specialization graph
+ let insert_result = def.add_impl_for_specialization(tcx, impl_def_id);
+
+ // insertion failed due to overlap
+ if let Err(overlap) = insert_result {
+ let mut err = struct_span_err!(tcx.sess,
+ tcx.span_of_impl(impl_def_id).unwrap(),
+ E0119,
+ "conflicting implementations of trait `{}`{}:",
+ overlap.trait_desc,
+ overlap.self_desc.clone().map_or(String::new(),
+ |ty| {
+ format!(" for type `{}`", ty)
+ }));
+
+ match tcx.span_of_impl(overlap.with_impl) {
+ Ok(span) => {
+ err.span_label(span, &format!("first implementation here"));
+ err.span_label(tcx.span_of_impl(impl_def_id).unwrap(),
+ &format!("conflicting implementation{}",
+ overlap.self_desc
+ .map_or(String::new(),
+ |ty| format!(" for `{}`", ty))));
+ }
+ Err(cname) => {
+ err.note(&format!("conflicting implementation in crate `{}`", cname));
}
}
+
+ err.emit();
}
- fn check_for_overlapping_inherent_impls(&self, ty_def_id: DefId) {
- let _task = self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapInherentCheck(ty_def_id));
-
- let inherent_impls = self.tcx.inherent_impls.borrow();
- let impls = match inherent_impls.get(&ty_def_id) {
- Some(impls) => impls,
- None => return,
- };
-
- for (i, &impl1_def_id) in impls.iter().enumerate() {
- for &impl2_def_id in &impls[(i + 1)..] {
- self.tcx.infer_ctxt((), Reveal::ExactMatch).enter(|infcx| {
- if traits::overlapping_impls(&infcx, impl1_def_id, impl2_def_id).is_some() {
- self.check_for_common_items_in_impls(impl1_def_id, impl2_def_id)
- }
- });
+ // check for overlap with the automatic `impl Trait for Trait`
+ if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
+ // This is something like impl Trait1 for Trait2. Illegal
+ // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
+
+ if data.principal().map_or(true, |p| !tcx.is_object_safe(p.def_id())) {
+ // This is an error, but it will be reported by wfcheck. Ignore it here.
+ // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
+ } else {
+ let mut supertrait_def_ids =
+ traits::supertrait_def_ids(tcx,
+ data.principal().unwrap().def_id());
+ if supertrait_def_ids.any(|d| d == trait_def_id) {
+ span_err!(tcx.sess,
+ tcx.span_of_impl(impl_def_id).unwrap(),
+ E0371,
+ "the object type `{}` automatically \
+ implements the trait `{}`",
+ trait_ref.self_ty(),
+ tcx.item_path_str(trait_def_id));
}
}
}
}
+struct OverlapChecker<'cx, 'tcx: 'cx> {
+ tcx: TyCtxt<'cx, 'tcx, 'tcx>,
+}
+
impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OverlapChecker<'cx, 'tcx> {
fn visit_item(&mut self, item: &'v hir::Item) {
match item.node {
- hir::ItemEnum(..) |
- hir::ItemStruct(..) |
- hir::ItemTrait(..) |
- hir::ItemUnion(..) => {
- let type_def_id = self.tcx.hir.local_def_id(item.id);
- self.check_for_overlapping_inherent_impls(type_def_id);
- }
-
hir::ItemDefaultImpl(..) => {
// look for another default impl; note that due to the
// general orphan/coherence rules, it must always be
let impl_def_id = self.tcx.hir.local_def_id(item.id);
let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
- let prev_default_impl = self.default_impls.insert(trait_ref.def_id, item.id);
- if let Some(prev_id) = prev_default_impl {
+ let prev_id = self.tcx.hir.trait_default_impl(trait_ref.def_id).unwrap();
+ if prev_id != item.id {
let mut err = struct_span_err!(self.tcx.sess,
self.tcx.span_of_impl(impl_def_id).unwrap(),
E0521,
}
}
hir::ItemImpl(.., Some(_), _, _) => {
- let impl_def_id = self.tcx.hir.local_def_id(item.id);
- let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap();
- let trait_def_id = trait_ref.def_id;
-
- if trait_ref.references_error() {
- debug!("coherence: skipping impl {:?} with error {:?}",
- impl_def_id, trait_ref);
- return
- }
-
- let _task =
- self.tcx.dep_graph.in_task(DepNode::CoherenceOverlapCheck(trait_def_id));
-
- let def = self.tcx.lookup_trait_def(trait_def_id);
-
- // attempt to insert into the specialization graph
- let insert_result = def.add_impl_for_specialization(self.tcx, impl_def_id);
-
- // insertion failed due to overlap
- if let Err(overlap) = insert_result {
- let mut err = struct_span_err!(self.tcx.sess,
- self.tcx.span_of_impl(impl_def_id).unwrap(),
- E0119,
- "conflicting implementations of trait `{}`{}:",
- overlap.trait_desc,
- overlap.self_desc.clone().map_or(String::new(),
- |ty| {
- format!(" for type `{}`", ty)
- }));
-
- match self.tcx.span_of_impl(overlap.with_impl) {
- Ok(span) => {
- err.span_label(span, &format!("first implementation here"));
- err.span_label(self.tcx.span_of_impl(impl_def_id).unwrap(),
- &format!("conflicting implementation{}",
- overlap.self_desc
- .map_or(String::new(),
- |ty| format!(" for `{}`", ty))));
- }
- Err(cname) => {
- err.note(&format!("conflicting implementation in crate `{}`", cname));
- }
- }
-
- err.emit();
- }
-
- // check for overlap with the automatic `impl Trait for Trait`
- if let ty::TyDynamic(ref data, ..) = trait_ref.self_ty().sty {
- // This is something like impl Trait1 for Trait2. Illegal
- // if Trait1 is a supertrait of Trait2 or Trait2 is not object safe.
-
- if data.principal().map_or(true, |p| !self.tcx.is_object_safe(p.def_id())) {
- // This is an error, but it will be reported by wfcheck. Ignore it here.
- // This is tested by `coherence-impl-trait-for-trait-object-safe.rs`.
- } else {
- let mut supertrait_def_ids =
- traits::supertrait_def_ids(self.tcx,
- data.principal().unwrap().def_id());
- if supertrait_def_ids.any(|d| d == trait_def_id) {
- span_err!(self.tcx.sess,
- item.span,
- E0371,
- "the object type `{}` automatically \
- implements the trait `{}`",
- trait_ref.self_ty(),
- self.tcx.item_path_str(trait_def_id));
- }
- }
- }
}
_ => {}
}
unsafety: hir::Unsafety,
polarity: hir::ImplPolarity) {
match self.tcx.impl_trait_ref(self.tcx.hir.local_def_id(item.id)) {
- None => {
- // Inherent impl.
- match unsafety {
- hir::Unsafety::Normal => {
- // OK
- }
- hir::Unsafety::Unsafe => {
- span_err!(self.tcx.sess,
- item.span,
- E0197,
- "inherent impls cannot be declared as unsafe");
- }
- }
- }
+ None => {}
Some(trait_ref) => {
let trait_def = self.tcx.lookup_trait_def(trait_ref.def_id);
hir::ItemDefaultImpl(unsafety, _) => {
self.check_unsafety_coherence(item, None, unsafety, hir::ImplPolarity::Positive);
}
- hir::ItemImpl(unsafety, polarity, ref generics, ..) => {
+ hir::ItemImpl(unsafety, polarity, ref generics, Some(_), _, _) => {
self.check_unsafety_coherence(item, Some(generics), unsafety, polarity);
}
_ => {}
for other items.
There are some shortcomings in this design:
-
-- Before walking the set of supertraits for a given trait, you must
- call `ensure_super_predicates` on that trait def-id. Otherwise,
- `item_super_predicates` will result in ICEs.
- Because the item generics include defaults, cycles through type
parameter defaults are illegal even if those defaults are never
employed. This is not necessarily a bug.
use constrained_type_params as ctp;
use middle::lang_items::SizedTraitLangItem;
use middle::const_val::ConstVal;
-use rustc_const_eval::EvalHint::UncheckedExprHint;
+use middle::resolve_lifetime as rl;
use rustc_const_eval::{ConstContext, report_const_eval_err};
use rustc::ty::subst::Substs;
-use rustc::ty::{ToPredicate, ImplContainer, AssociatedItemContainer, TraitContainer, ReprOptions};
+use rustc::ty::{ToPredicate, ReprOptions};
use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt};
+use rustc::ty::maps::Providers;
use rustc::ty::util::IntTypeExt;
use rustc::dep_graph::DepNode;
-use util::common::{ErrorReported, MemoizationMap};
+use util::common::MemoizationMap;
use util::nodemap::{NodeMap, FxHashMap};
-use CrateCtxt;
use rustc_const_math::ConstInt;
use std::cell::RefCell;
+use std::collections::BTreeMap;
-use syntax::{abi, ast, attr};
+use syntax::{abi, ast};
+use syntax::codemap::Spanned;
use syntax::symbol::{Symbol, keywords};
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
use rustc::hir::{self, map as hir_map};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
///////////////////////////////////////////////////////////////////////////
// Main entry point
-pub fn collect_item_types(ccx: &CrateCtxt) {
- let mut visitor = CollectItemTypesVisitor { ccx: ccx };
- ccx.tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor());
+pub fn collect_item_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
+ let mut visitor = CollectItemTypesVisitor { tcx: tcx };
+ tcx.visit_all_item_likes_in_krate(DepNode::CollectItem, &mut visitor.as_deep_visitor());
+}
+
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
+ ty,
+ generics,
+ predicates,
+ super_predicates,
+ type_param_predicates,
+ trait_def,
+ adt_def,
+ impl_trait_ref,
+ ..*providers
+ };
}
///////////////////////////////////////////////////////////////////////////
/// available in various different forms at various points in the
/// process. So we can't just store a pointer to e.g. the AST or the
/// parsed ty form, we have to be more flexible. To this end, the
-/// `ItemCtxt` is parameterized by a `GetTypeParameterBounds` object
-/// that it uses to satisfy `get_type_parameter_bounds` requests.
-/// This object might draw the information from the AST
-/// (`hir::Generics`) or it might draw from a `ty::GenericPredicates`
-/// or both (a tuple).
+/// `ItemCtxt` is parameterized by a `DefId` that it uses to satisfy
+/// `get_type_parameter_bounds` requests, drawing the information from
+/// the AST (`hir::Generics`), recursively.
struct ItemCtxt<'a,'tcx:'a> {
- ccx: &'a CrateCtxt<'a,'tcx>,
- param_bounds: &'a (GetTypeParameterBounds<'tcx>+'a),
-}
-
-#[derive(Copy, Clone, PartialEq, Eq)]
-pub enum AstConvRequest {
- GetGenerics(DefId),
- GetItemTypeScheme(DefId),
- GetTraitDef(DefId),
- EnsureSuperPredicates(DefId),
- GetTypeParameterBounds(ast::NodeId),
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ item_def_id: DefId,
}
///////////////////////////////////////////////////////////////////////////
struct CollectItemTypesVisitor<'a, 'tcx: 'a> {
- ccx: &'a CrateCtxt<'a, 'tcx>
+ tcx: TyCtxt<'a, 'tcx, 'tcx>
}
impl<'a, 'tcx> CollectItemTypesVisitor<'a, 'tcx> {
fn with_collect_item_sig<OP>(&self, id: ast::NodeId, op: OP)
where OP: FnOnce()
{
- let def_id = self.ccx.tcx.hir.local_def_id(id);
- self.ccx.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || {
- self.ccx.tcx.hir.read(id);
+ let def_id = self.tcx.hir.local_def_id(id);
+ self.tcx.dep_graph.with_task(DepNode::CollectItemSig(def_id), || {
+ self.tcx.hir.read(id);
op();
});
}
impl<'a, 'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::OnlyBodies(&self.ccx.tcx.hir)
+ NestedVisitorMap::OnlyBodies(&self.tcx.hir)
}
fn visit_item(&mut self, item: &'tcx hir::Item) {
- self.with_collect_item_sig(item.id, || convert_item(self.ccx, item));
+ self.with_collect_item_sig(item.id, || convert_item(self.tcx, item));
intravisit::walk_item(self, item);
}
+ fn visit_generics(&mut self, generics: &'tcx hir::Generics) {
+ for param in &generics.ty_params {
+ if param.default.is_some() {
+ let def_id = self.tcx.hir.local_def_id(param.id);
+ self.tcx.item_type(def_id);
+ }
+ }
+ intravisit::walk_generics(self, generics);
+ }
+
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
if let hir::ExprClosure(..) = expr.node {
- let def_id = self.ccx.tcx.hir.local_def_id(expr.id);
- generics_of_def_id(self.ccx, def_id);
- type_of_def_id(self.ccx, def_id);
+ let def_id = self.tcx.hir.local_def_id(expr.id);
+ self.tcx.item_generics(def_id);
+ self.tcx.item_type(def_id);
}
intravisit::walk_expr(self, expr);
}
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
if let hir::TyImplTrait(..) = ty.node {
- let def_id = self.ccx.tcx.hir.local_def_id(ty.id);
- generics_of_def_id(self.ccx, def_id);
+ let def_id = self.tcx.hir.local_def_id(ty.id);
+ self.tcx.item_generics(def_id);
+ self.tcx.item_predicates(def_id);
}
intravisit::walk_ty(self, ty);
}
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
self.with_collect_item_sig(trait_item.id, || {
- convert_trait_item(self.ccx, trait_item)
+ convert_trait_item(self.tcx, trait_item)
});
intravisit::walk_trait_item(self, trait_item);
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.with_collect_item_sig(impl_item.id, || {
- convert_impl_item(self.ccx, impl_item)
+ convert_impl_item(self.tcx, impl_item)
});
intravisit::walk_impl_item(self, impl_item);
}
///////////////////////////////////////////////////////////////////////////
// Utility types and common code for the above passes.
-impl<'a,'tcx> CrateCtxt<'a,'tcx> {
- fn icx(&'a self, param_bounds: &'a GetTypeParameterBounds<'tcx>) -> ItemCtxt<'a,'tcx> {
+impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
+ fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_def_id: DefId)
+ -> ItemCtxt<'a,'tcx> {
ItemCtxt {
- ccx: self,
- param_bounds: param_bounds,
- }
- }
-
- fn cycle_check<F,R>(&self,
- span: Span,
- request: AstConvRequest,
- code: F)
- -> Result<R,ErrorReported>
- where F: FnOnce() -> Result<R,ErrorReported>
- {
- {
- let mut stack = self.stack.borrow_mut();
- if let Some((i, _)) = stack.iter().enumerate().rev().find(|&(_, r)| *r == request) {
- let cycle = &stack[i..];
- self.report_cycle(span, cycle);
- return Err(ErrorReported);
- }
- stack.push(request);
+ tcx: tcx,
+ item_def_id: item_def_id,
}
-
- let result = code();
-
- self.stack.borrow_mut().pop();
- result
- }
-
- fn report_cycle(&self,
- span: Span,
- cycle: &[AstConvRequest])
- {
- assert!(!cycle.is_empty());
- let tcx = self.tcx;
-
- let mut err = struct_span_err!(tcx.sess, span, E0391,
- "unsupported cyclic reference between types/traits detected");
- err.span_label(span, &format!("cyclic reference"));
-
- match cycle[0] {
- AstConvRequest::GetGenerics(def_id) |
- AstConvRequest::GetItemTypeScheme(def_id) |
- AstConvRequest::GetTraitDef(def_id) => {
- err.note(
- &format!("the cycle begins when processing `{}`...",
- tcx.item_path_str(def_id)));
- }
- AstConvRequest::EnsureSuperPredicates(def_id) => {
- err.note(
- &format!("the cycle begins when computing the supertraits of `{}`...",
- tcx.item_path_str(def_id)));
- }
- AstConvRequest::GetTypeParameterBounds(id) => {
- let def = tcx.type_parameter_def(id);
- err.note(
- &format!("the cycle begins when computing the bounds \
- for type parameter `{}`...",
- def.name));
- }
- }
-
- for request in &cycle[1..] {
- match *request {
- AstConvRequest::GetGenerics(def_id) |
- AstConvRequest::GetItemTypeScheme(def_id) |
- AstConvRequest::GetTraitDef(def_id) => {
- err.note(
- &format!("...which then requires processing `{}`...",
- tcx.item_path_str(def_id)));
- }
- AstConvRequest::EnsureSuperPredicates(def_id) => {
- err.note(
- &format!("...which then requires computing the supertraits of `{}`...",
- tcx.item_path_str(def_id)));
- }
- AstConvRequest::GetTypeParameterBounds(id) => {
- let def = tcx.type_parameter_def(id);
- err.note(
- &format!("...which then requires computing the bounds \
- for type parameter `{}`...",
- def.name));
- }
- }
- }
-
- match cycle[0] {
- AstConvRequest::GetGenerics(def_id) |
- AstConvRequest::GetItemTypeScheme(def_id) |
- AstConvRequest::GetTraitDef(def_id) => {
- err.note(
- &format!("...which then again requires processing `{}`, completing the cycle.",
- tcx.item_path_str(def_id)));
- }
- AstConvRequest::EnsureSuperPredicates(def_id) => {
- err.note(
- &format!("...which then again requires computing the supertraits of `{}`, \
- completing the cycle.",
- tcx.item_path_str(def_id)));
- }
- AstConvRequest::GetTypeParameterBounds(id) => {
- let def = tcx.type_parameter_def(id);
- err.note(
- &format!("...which then again requires computing the bounds \
- for type parameter `{}`, completing the cycle.",
- def.name));
- }
- }
- err.emit();
- }
-
- /// Loads the trait def for a given trait, returning ErrorReported if a cycle arises.
- fn get_trait_def(&self, def_id: DefId)
- -> &'tcx ty::TraitDef
- {
- let tcx = self.tcx;
-
- if let Some(trait_id) = tcx.hir.as_local_node_id(def_id) {
- let item = match tcx.hir.get(trait_id) {
- hir_map::NodeItem(item) => item,
- _ => bug!("get_trait_def({:?}): not an item", trait_id)
- };
-
- generics_of_def_id(self, def_id);
- trait_def_of_item(self, &item)
- } else {
- tcx.lookup_trait_def(def_id)
- }
- }
-
- /// Ensure that the (transitive) super predicates for
- /// `trait_def_id` are available. This will report a cycle error
- /// if a trait `X` (transitively) extends itself in some form.
- fn ensure_super_predicates(&self, span: Span, trait_def_id: DefId)
- -> Result<(), ErrorReported>
- {
- self.cycle_check(span, AstConvRequest::EnsureSuperPredicates(trait_def_id), || {
- let def_ids = ensure_super_predicates_step(self, trait_def_id);
-
- for def_id in def_ids {
- self.ensure_super_predicates(span, def_id)?;
- }
-
- Ok(())
- })
}
}
}
impl<'a, 'tcx> AstConv<'tcx, 'tcx> for ItemCtxt<'a, 'tcx> {
- fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.ccx.tcx }
+ fn tcx<'b>(&'b self) -> TyCtxt<'b, 'tcx, 'tcx> { self.tcx }
fn ast_ty_to_ty_cache(&self) -> &RefCell<NodeMap<Ty<'tcx>>> {
- &self.ccx.ast_ty_to_ty_cache
- }
-
- fn get_generics(&self, span: Span, id: DefId)
- -> Result<&'tcx ty::Generics<'tcx>, ErrorReported>
- {
- self.ccx.cycle_check(span, AstConvRequest::GetGenerics(id), || {
- Ok(generics_of_def_id(self.ccx, id))
- })
- }
-
- fn get_item_type(&self, span: Span, id: DefId) -> Result<Ty<'tcx>, ErrorReported> {
- self.ccx.cycle_check(span, AstConvRequest::GetItemTypeScheme(id), || {
- Ok(type_of_def_id(self.ccx, id))
- })
- }
-
- fn get_trait_def(&self, span: Span, id: DefId)
- -> Result<&'tcx ty::TraitDef, ErrorReported>
- {
- self.ccx.cycle_check(span, AstConvRequest::GetTraitDef(id), || {
- Ok(self.ccx.get_trait_def(id))
- })
+ &self.tcx.ast_ty_to_ty_cache
}
- fn ensure_super_predicates(&self,
- span: Span,
- trait_def_id: DefId)
- -> Result<(), ErrorReported>
- {
- debug!("ensure_super_predicates(trait_def_id={:?})",
- trait_def_id);
-
- self.ccx.ensure_super_predicates(span, trait_def_id)
- }
-
-
fn get_type_parameter_bounds(&self,
span: Span,
- node_id: ast::NodeId)
- -> Result<Vec<ty::PolyTraitRef<'tcx>>, ErrorReported>
+ def_id: DefId)
+ -> ty::GenericPredicates<'tcx>
{
- self.ccx.cycle_check(span, AstConvRequest::GetTypeParameterBounds(node_id), || {
- let v = self.param_bounds.get_type_parameter_bounds(self, span, node_id)
- .into_iter()
- .filter_map(|p| p.to_opt_poly_trait_ref())
- .collect();
- Ok(v)
- })
+ ty::queries::type_param_predicates::get(self.tcx, span, (self.item_def_id, def_id))
}
fn get_free_substs(&self) -> Option<&Substs<'tcx>> {
}
}
-/// Interface used to find the bounds on a type parameter from within
-/// an `ItemCtxt`. This allows us to use multiple kinds of sources.
-trait GetTypeParameterBounds<'tcx> {
- fn get_type_parameter_bounds(&self,
- astconv: &AstConv<'tcx, 'tcx>,
- span: Span,
- node_id: ast::NodeId)
- -> Vec<ty::Predicate<'tcx>>;
-}
-
-/// Find bounds from both elements of the tuple.
-impl<'a,'b,'tcx,A,B> GetTypeParameterBounds<'tcx> for (&'a A,&'b B)
- where A : GetTypeParameterBounds<'tcx>, B : GetTypeParameterBounds<'tcx>
-{
- fn get_type_parameter_bounds(&self,
- astconv: &AstConv<'tcx, 'tcx>,
- span: Span,
- node_id: ast::NodeId)
- -> Vec<ty::Predicate<'tcx>>
- {
- let mut v = self.0.get_type_parameter_bounds(astconv, span, node_id);
- v.extend(self.1.get_type_parameter_bounds(astconv, span, node_id));
- v
- }
-}
+fn type_param_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ (item_def_id, def_id): (DefId, DefId))
+ -> ty::GenericPredicates<'tcx> {
+ use rustc::hir::map::*;
+ use rustc::hir::*;
+
+ // In the AST, bounds can derive from two places. Either
+ // written inline like `<T:Foo>` or in a where clause like
+ // `where T:Foo`.
+
+ let param_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let param_owner = tcx.hir.ty_param_owner(param_id);
+ let param_owner_def_id = tcx.hir.local_def_id(param_owner);
+ let generics = tcx.item_generics(param_owner_def_id);
+ let index = generics.type_param_to_index[&def_id.index];
+ let ty = tcx.mk_param(index, tcx.hir.ty_param_name(param_id));
+
+ // Don't look for bounds where the type parameter isn't in scope.
+ let parent = if item_def_id == param_owner_def_id {
+ None
+ } else {
+ tcx.item_generics(item_def_id).parent
+ };
-/// Empty set of bounds.
-impl<'tcx> GetTypeParameterBounds<'tcx> for () {
- fn get_type_parameter_bounds(&self,
- _astconv: &AstConv<'tcx, 'tcx>,
- _span: Span,
- _node_id: ast::NodeId)
- -> Vec<ty::Predicate<'tcx>>
- {
- Vec::new()
- }
-}
+ let mut result = parent.map_or(ty::GenericPredicates {
+ parent: None,
+ predicates: vec![]
+ }, |parent| {
+ let icx = ItemCtxt::new(tcx, parent);
+ icx.get_type_parameter_bounds(DUMMY_SP, def_id)
+ });
-/// Find bounds from the parsed and converted predicates. This is
-/// used when converting methods, because by that time the predicates
-/// from the trait/impl have been fully converted.
-impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> {
- fn get_type_parameter_bounds(&self,
- astconv: &AstConv<'tcx, 'tcx>,
- span: Span,
- node_id: ast::NodeId)
- -> Vec<ty::Predicate<'tcx>>
- {
- let def = astconv.tcx().type_parameter_def(node_id);
+ let item_node_id = tcx.hir.as_local_node_id(item_def_id).unwrap();
+ let ast_generics = match tcx.hir.get(item_node_id) {
+ NodeTraitItem(item) => {
+ match item.node {
+ TraitItemKind::Method(ref sig, _) => &sig.generics,
+ _ => return result
+ }
+ }
- let mut results = self.parent.map_or(vec![], |def_id| {
- let parent = astconv.tcx().item_predicates(def_id);
- parent.get_type_parameter_bounds(astconv, span, node_id)
- });
+ NodeImplItem(item) => {
+ match item.node {
+ ImplItemKind::Method(ref sig, _) => &sig.generics,
+ _ => return result
+ }
+ }
- results.extend(self.predicates.iter().filter(|predicate| {
- match **predicate {
- ty::Predicate::Trait(ref data) => {
- data.skip_binder().self_ty().is_param(def.index)
- }
- ty::Predicate::TypeOutlives(ref data) => {
- data.skip_binder().0.is_param(def.index)
- }
- ty::Predicate::Equate(..) |
- ty::Predicate::RegionOutlives(..) |
- ty::Predicate::WellFormed(..) |
- ty::Predicate::ObjectSafe(..) |
- ty::Predicate::ClosureKind(..) |
- ty::Predicate::Projection(..) => {
- false
+ NodeItem(item) => {
+ match item.node {
+ ItemFn(.., ref generics, _) |
+ ItemImpl(_, _, ref generics, ..) |
+ ItemTy(_, ref generics) |
+ ItemEnum(_, ref generics) |
+ ItemStruct(_, ref generics) |
+ ItemUnion(_, ref generics) => generics,
+ ItemTrait(_, ref generics, ..) => {
+ // Implied `Self: Trait` and supertrait bounds.
+ if param_id == item_node_id {
+ result.predicates.push(ty::TraitRef {
+ def_id: item_def_id,
+ substs: Substs::identity_for_item(tcx, item_def_id)
+ }.to_predicate());
+ }
+ generics
}
+ _ => return result
}
- }).cloned());
+ }
- results
- }
-}
+ NodeForeignItem(item) => {
+ match item.node {
+ ForeignItemFn(_, _, ref generics) => generics,
+ _ => return result
+ }
+ }
-/// Find bounds from hir::Generics. This requires scanning through the
-/// AST. We do this to avoid having to convert *all* the bounds, which
-/// would create artificial cycles. Instead we can only convert the
-/// bounds for a type parameter `X` if `X::Foo` is used.
-impl<'tcx> GetTypeParameterBounds<'tcx> for hir::Generics {
- fn get_type_parameter_bounds(&self,
- astconv: &AstConv<'tcx, 'tcx>,
- _: Span,
- node_id: ast::NodeId)
- -> Vec<ty::Predicate<'tcx>>
- {
- // In the AST, bounds can derive from two places. Either
- // written inline like `<T:Foo>` or in a where clause like
- // `where T:Foo`.
+ _ => return result
+ };
- let def = astconv.tcx().type_parameter_def(node_id);
- let ty = astconv.tcx().mk_param_from_def(&def);
+ let icx = ItemCtxt::new(tcx, item_def_id);
+ result.predicates.extend(
+ icx.type_parameter_bounds_in_generics(ast_generics, param_id, ty));
+ result
+}
+impl<'a, 'tcx> ItemCtxt<'a, 'tcx> {
+ /// Find bounds from hir::Generics. This requires scanning through the
+ /// AST. We do this to avoid having to convert *all* the bounds, which
+ /// would create artificial cycles. Instead we can only convert the
+ /// bounds for a type parameter `X` if `X::Foo` is used.
+ fn type_parameter_bounds_in_generics(&self,
+ ast_generics: &hir::Generics,
+ param_id: ast::NodeId,
+ ty: Ty<'tcx>)
+ -> Vec<ty::Predicate<'tcx>>
+ {
let from_ty_params =
- self.ty_params
+ ast_generics.ty_params
.iter()
- .filter(|p| p.id == node_id)
+ .filter(|p| p.id == param_id)
.flat_map(|p| p.bounds.iter())
- .flat_map(|b| predicates_from_bound(astconv, ty, b));
+ .flat_map(|b| predicates_from_bound(self, ty, b));
let from_where_clauses =
- self.where_clause
+ ast_generics.where_clause
.predicates
.iter()
.filter_map(|wp| match *wp {
hir::WherePredicate::BoundPredicate(ref bp) => Some(bp),
_ => None
})
- .filter(|bp| is_param(astconv.tcx(), &bp.bounded_ty, node_id))
+ .filter(|bp| is_param(self.tcx, &bp.bounded_ty, param_id))
.flat_map(|bp| bp.bounds.iter())
- .flat_map(|b| predicates_from_bound(astconv, ty, b));
+ .flat_map(|b| predicates_from_bound(self, ty, b));
from_ty_params.chain(from_where_clauses).collect()
}
}
}
-fn convert_field<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- struct_generics: &'tcx ty::Generics<'tcx>,
- struct_predicates: &ty::GenericPredicates<'tcx>,
- field: &hir::StructField,
- ty_f: &'tcx ty::FieldDef)
-{
- let tt = ccx.icx(struct_predicates).to_ty(&field.ty);
- ccx.tcx.item_types.borrow_mut().insert(ty_f.did, tt);
-
- let def_id = ccx.tcx.hir.local_def_id(field.id);
- assert_eq!(def_id, ty_f.did);
- ccx.tcx.generics.borrow_mut().insert(def_id, struct_generics);
- ccx.tcx.predicates.borrow_mut().insert(def_id, struct_predicates.clone());
-}
-
-fn convert_method<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- id: ast::NodeId,
- sig: &hir::MethodSig,
- rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) {
- let def_id = ccx.tcx.hir.local_def_id(id);
- let ty_generics = generics_of_def_id(ccx, def_id);
-
- let ty_generic_predicates =
- ty_generic_predicates(ccx, &sig.generics, ty_generics.parent, vec![], false);
-
- let fty = AstConv::ty_of_fn(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
- sig.unsafety, sig.abi, &sig.decl);
-
- let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
- ccx.tcx.hir.span(id), def_id);
- let fty = ccx.tcx.mk_fn_def(def_id, substs, fty);
- ccx.tcx.item_types.borrow_mut().insert(def_id, fty);
- ccx.tcx.predicates.borrow_mut().insert(def_id, ty_generic_predicates);
-}
-
-fn convert_associated_const<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- container: AssociatedItemContainer,
- id: ast::NodeId,
- ty: ty::Ty<'tcx>)
-{
- let predicates = ty::GenericPredicates {
- parent: Some(container.id()),
- predicates: vec![]
- };
- let def_id = ccx.tcx.hir.local_def_id(id);
- ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
- ccx.tcx.item_types.borrow_mut().insert(def_id, ty);
-}
-
-fn convert_associated_type<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- container: AssociatedItemContainer,
- id: ast::NodeId,
- ty: Option<Ty<'tcx>>)
-{
- let predicates = ty::GenericPredicates {
- parent: Some(container.id()),
- predicates: vec![]
- };
- let def_id = ccx.tcx.hir.local_def_id(id);
- ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
-
- if let Some(ty) = ty {
- ccx.tcx.item_types.borrow_mut().insert(def_id, ty);
- }
-}
-
-fn ensure_no_ty_param_bounds(ccx: &CrateCtxt,
- span: Span,
- generics: &hir::Generics,
- thing: &'static str) {
+fn ensure_no_ty_param_bounds(tcx: TyCtxt,
+ span: Span,
+ generics: &hir::Generics,
+ thing: &'static str) {
let mut warn = false;
for ty_param in generics.ty_params.iter() {
// eventually accept these, but it will not be
// part of this PR. Still, convert to warning to
// make bootstrapping easier.
- span_warn!(ccx.tcx.sess, span, E0122,
+ span_warn!(tcx.sess, span, E0122,
"trait bounds are not (yet) enforced \
in {} definitions",
thing);
}
}
-fn convert_item(ccx: &CrateCtxt, it: &hir::Item) {
- let tcx = ccx.tcx;
+fn convert_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &hir::Item) {
debug!("convert: item {} with id {}", it.name, it.id);
- let def_id = ccx.tcx.hir.local_def_id(it.id);
+ let def_id = tcx.hir.local_def_id(it.id);
match it.node {
// These don't define types.
hir::ItemExternCrate(_) | hir::ItemUse(..) | hir::ItemMod(_) => {
}
hir::ItemForeignMod(ref foreign_mod) => {
for item in &foreign_mod.items {
- convert_foreign_item(ccx, item);
+ let def_id = tcx.hir.local_def_id(item.id);
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.item_predicates(def_id);
}
}
hir::ItemEnum(ref enum_definition, _) => {
- let ty = type_of_def_id(ccx, def_id);
- let generics = generics_of_def_id(ccx, def_id);
- let predicates = predicates_of_item(ccx, it);
- convert_enum_variant_types(ccx,
- tcx.lookup_adt_def(ccx.tcx.hir.local_def_id(it.id)),
- ty,
- generics,
- predicates,
- &enum_definition.variants);
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.item_predicates(def_id);
+ convert_enum_variant_types(tcx, def_id, &enum_definition.variants);
},
- hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
- let trait_ref =
- AstConv::instantiate_mono_trait_ref(&ccx.icx(&()),
- ast_trait_ref,
- tcx.mk_self_type());
-
- tcx.record_trait_has_default_impl(trait_ref.def_id);
-
- tcx.impl_trait_refs.borrow_mut().insert(ccx.tcx.hir.local_def_id(it.id),
- Some(trait_ref));
+ hir::ItemDefaultImpl(..) => {
+ tcx.impl_trait_ref(def_id);
}
- hir::ItemImpl(..,
- ref generics,
- ref opt_trait_ref,
- ref selfty,
- _) => {
- // Create generics from the generics specified in the impl head.
- debug!("convert: ast_generics={:?}", generics);
- generics_of_def_id(ccx, def_id);
- let mut ty_predicates =
- ty_generic_predicates(ccx, generics, None, vec![], false);
-
- debug!("convert: impl_bounds={:?}", ty_predicates);
-
- let selfty = ccx.icx(&ty_predicates).to_ty(&selfty);
- tcx.item_types.borrow_mut().insert(def_id, selfty);
-
- let trait_ref = opt_trait_ref.as_ref().map(|ast_trait_ref| {
- AstConv::instantiate_mono_trait_ref(&ccx.icx(&ty_predicates),
- ast_trait_ref,
- selfty)
- });
- tcx.impl_trait_refs.borrow_mut().insert(def_id, trait_ref);
-
- // Subtle: before we store the predicates into the tcx, we
- // sort them so that predicates like `T: Foo<Item=U>` come
- // before uses of `U`. This avoids false ambiguity errors
- // in trait checking. See `setup_constraining_predicates`
- // for details.
- ctp::setup_constraining_predicates(&mut ty_predicates.predicates,
- trait_ref,
- &mut ctp::parameters_for_impl(selfty, trait_ref));
-
- tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
+ hir::ItemImpl(..) => {
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.impl_trait_ref(def_id);
+ tcx.item_predicates(def_id);
},
hir::ItemTrait(..) => {
- generics_of_def_id(ccx, def_id);
- trait_def_of_item(ccx, it);
- let _: Result<(), ErrorReported> = // any error is already reported, can ignore
- ccx.ensure_super_predicates(it.span, def_id);
- convert_trait_predicates(ccx, it);
+ tcx.item_generics(def_id);
+ tcx.lookup_trait_def(def_id);
+ ty::queries::super_predicates::get(tcx, it.span, def_id);
+ tcx.item_predicates(def_id);
},
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
- let ty = type_of_def_id(ccx, def_id);
- let generics = generics_of_def_id(ccx, def_id);
- let predicates = predicates_of_item(ccx, it);
-
- let variant = tcx.lookup_adt_def(def_id).struct_variant();
-
- for (f, ty_f) in struct_def.fields().iter().zip(variant.fields.iter()) {
- convert_field(ccx, generics, &predicates, f, ty_f)
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.item_predicates(def_id);
+
+ for f in struct_def.fields() {
+ let def_id = tcx.hir.local_def_id(f.id);
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.item_predicates(def_id);
}
if !struct_def.is_struct() {
- convert_variant_ctor(ccx, struct_def.id(), variant, ty, predicates);
+ convert_variant_ctor(tcx, struct_def.id());
}
},
hir::ItemTy(_, ref generics) => {
- ensure_no_ty_param_bounds(ccx, it.span, generics, "type");
- type_of_def_id(ccx, def_id);
- generics_of_def_id(ccx, def_id);
- predicates_of_item(ccx, it);
+ ensure_no_ty_param_bounds(tcx, it.span, generics, "type");
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.item_predicates(def_id);
},
_ => {
- type_of_def_id(ccx, def_id);
- generics_of_def_id(ccx, def_id);
- predicates_of_item(ccx, it);
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.item_predicates(def_id);
},
}
}
-fn convert_trait_item(ccx: &CrateCtxt, trait_item: &hir::TraitItem) {
- let tcx = ccx.tcx;
-
- // we can lookup details about the trait because items are visited
- // before trait-items
- let trait_def_id = tcx.hir.get_parent_did(trait_item.id);
- let trait_predicates = tcx.item_predicates(trait_def_id);
+fn convert_trait_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_item: &hir::TraitItem) {
+ let def_id = tcx.hir.local_def_id(trait_item.id);
+ tcx.item_generics(def_id);
match trait_item.node {
- hir::TraitItemKind::Const(ref ty, _) => {
- let const_def_id = ccx.tcx.hir.local_def_id(trait_item.id);
- generics_of_def_id(ccx, const_def_id);
- let ty = ccx.icx(&trait_predicates).to_ty(&ty);
- convert_associated_const(ccx,
- TraitContainer(trait_def_id),
- trait_item.id,
- ty);
+ hir::TraitItemKind::Const(..) |
+ hir::TraitItemKind::Type(_, Some(_)) |
+ hir::TraitItemKind::Method(..) => {
+ tcx.item_type(def_id);
}
- hir::TraitItemKind::Type(_, ref opt_ty) => {
- let type_def_id = ccx.tcx.hir.local_def_id(trait_item.id);
- generics_of_def_id(ccx, type_def_id);
-
- let typ = opt_ty.as_ref().map({
- |ty| ccx.icx(&trait_predicates).to_ty(&ty)
- });
-
- convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
- }
+ hir::TraitItemKind::Type(_, None) => {}
+ };
- hir::TraitItemKind::Method(ref sig, _) => {
- convert_method(ccx, trait_item.id, sig, &trait_predicates);
- }
- }
+ tcx.item_predicates(def_id);
}
-fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
- let tcx = ccx.tcx;
-
- // we can lookup details about the impl because items are visited
- // before impl-items
- let impl_def_id = tcx.hir.get_parent_did(impl_item.id);
- let impl_predicates = tcx.item_predicates(impl_def_id);
- let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
-
- match impl_item.node {
- hir::ImplItemKind::Const(ref ty, _) => {
- let const_def_id = ccx.tcx.hir.local_def_id(impl_item.id);
- generics_of_def_id(ccx, const_def_id);
- let ty = ccx.icx(&impl_predicates).to_ty(&ty);
- convert_associated_const(ccx,
- ImplContainer(impl_def_id),
- impl_item.id,
- ty);
- }
-
- hir::ImplItemKind::Type(ref ty) => {
- let type_def_id = ccx.tcx.hir.local_def_id(impl_item.id);
- generics_of_def_id(ccx, type_def_id);
-
- if impl_trait_ref.is_none() {
- span_err!(tcx.sess, impl_item.span, E0202,
- "associated types are not allowed in inherent impls");
- }
-
- let typ = ccx.icx(&impl_predicates).to_ty(ty);
-
- convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
- }
-
- hir::ImplItemKind::Method(ref sig, _) => {
- convert_method(ccx, impl_item.id, sig, &impl_predicates);
- }
- }
+fn convert_impl_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, impl_item: &hir::ImplItem) {
+ let def_id = tcx.hir.local_def_id(impl_item.id);
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.item_predicates(def_id);
}
-fn convert_variant_ctor<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- ctor_id: ast::NodeId,
- variant: &'tcx ty::VariantDef,
- ty: Ty<'tcx>,
- predicates: ty::GenericPredicates<'tcx>) {
- let tcx = ccx.tcx;
+fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ ctor_id: ast::NodeId) {
let def_id = tcx.hir.local_def_id(ctor_id);
- generics_of_def_id(ccx, def_id);
- let ctor_ty = match variant.ctor_kind {
- CtorKind::Fictive | CtorKind::Const => ty,
- CtorKind::Fn => {
- let inputs = variant.fields.iter().map(|field| tcx.item_type(field.did));
- let substs = mk_item_substs(&ccx.icx(&predicates), ccx.tcx.hir.span(ctor_id), def_id);
- tcx.mk_fn_def(def_id, substs, tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Normal,
- abi: abi::Abi::Rust,
- sig: ty::Binder(ccx.tcx.mk_fn_sig(inputs, ty, false))
- }))
- }
- };
- tcx.item_types.borrow_mut().insert(def_id, ctor_ty);
- tcx.predicates.borrow_mut().insert(tcx.hir.local_def_id(ctor_id), predicates);
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.item_predicates(def_id);
}
-fn convert_enum_variant_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- def: &'tcx ty::AdtDef,
- ty: Ty<'tcx>,
- generics: &'tcx ty::Generics<'tcx>,
- predicates: ty::GenericPredicates<'tcx>,
+fn evaluate_disr_expr<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ body: hir::BodyId)
+ -> Result<ConstVal<'tcx>, ()> {
+ let e = &tcx.hir.body(body).value;
+ ConstContext::new(tcx, body).eval(e).map_err(|err| {
+ // enum variant evaluation happens before the global constant check
+ // so we need to report the real error
+ report_const_eval_err(tcx, &err, e.span, "enum discriminant");
+ })
+}
+
+fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId,
variants: &[hir::Variant]) {
- // fill the field types
- for (variant, ty_variant) in variants.iter().zip(def.variants.iter()) {
- for (f, ty_f) in variant.node.data.fields().iter().zip(ty_variant.fields.iter()) {
- convert_field(ccx, generics, &predicates, f, ty_f)
+ let def = tcx.lookup_adt_def(def_id);
+ let repr_type = def.repr.discr_type();
+ let initial = repr_type.initial_discriminant(tcx);
+ let mut prev_discr = None::<ConstInt>;
+
+ // fill the discriminant values and field types
+ for variant in variants {
+ let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr());
+ prev_discr = Some(if let Some(e) = variant.node.disr_expr {
+ let expr_did = tcx.hir.local_def_id(e.node_id);
+ let result = tcx.maps.monomorphic_const_eval.memoize(expr_did, || {
+ evaluate_disr_expr(tcx, e)
+ });
+
+ match result {
+ Ok(ConstVal::Integral(x)) => Some(x),
+ _ => None
+ }
+ } else if let Some(discr) = repr_type.disr_incr(tcx, prev_discr) {
+ Some(discr)
+ } else {
+ struct_span_err!(tcx.sess, variant.span, E0370,
+ "enum discriminant overflowed")
+ .span_label(variant.span, &format!("overflowed on value after {}",
+ prev_discr.unwrap()))
+ .note(&format!("explicitly set `{} = {}` if that is desired outcome",
+ variant.node.name, wrapped_discr))
+ .emit();
+ None
+ }.unwrap_or(wrapped_discr));
+
+ for f in variant.node.data.fields() {
+ let def_id = tcx.hir.local_def_id(f.id);
+ tcx.item_generics(def_id);
+ tcx.item_type(def_id);
+ tcx.item_predicates(def_id);
}
// Convert the ctor, if any. This also registers the variant as
// an item.
- convert_variant_ctor(
- ccx,
- variant.node.data.id(),
- ty_variant,
- ty,
- predicates.clone()
- );
+ convert_variant_ctor(tcx, variant.node.data.id());
}
}
-fn convert_struct_variant<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn convert_struct_variant<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
did: DefId,
name: ast::Name,
- disr_val: ty::Disr,
+ discr: ty::VariantDiscr,
def: &hir::VariantData)
-> ty::VariantDef {
let mut seen_fields: FxHashMap<ast::Name, Span> = FxHashMap();
- let node_id = ccx.tcx.hir.as_local_node_id(did).unwrap();
+ let node_id = tcx.hir.as_local_node_id(did).unwrap();
let fields = def.fields().iter().map(|f| {
- let fid = ccx.tcx.hir.local_def_id(f.id);
+ let fid = tcx.hir.local_def_id(f.id);
let dup_span = seen_fields.get(&f.name).cloned();
if let Some(prev_span) = dup_span {
- struct_span_err!(ccx.tcx.sess, f.span, E0124,
+ struct_span_err!(tcx.sess, f.span, E0124,
"field `{}` is already declared",
f.name)
.span_label(f.span, &"field already declared")
ty::FieldDef {
did: fid,
name: f.name,
- vis: ty::Visibility::from_hir(&f.vis, node_id, ccx.tcx)
+ vis: ty::Visibility::from_hir(&f.vis, node_id, tcx)
}
}).collect();
ty::VariantDef {
did: did,
name: name,
- disr_val: disr_val,
+ discr: discr,
fields: fields,
ctor_kind: CtorKind::from_hir(def),
}
}
-fn convert_struct_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- it: &hir::Item,
- def: &hir::VariantData)
- -> &'tcx ty::AdtDef
-{
- let did = ccx.tcx.hir.local_def_id(it.id);
- // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
- let ctor_id = if !def.is_struct() { Some(ccx.tcx.hir.local_def_id(def.id())) } else { None };
- let variants = vec![convert_struct_variant(ccx, ctor_id.unwrap_or(did), it.name, 0, def)];
- let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Struct, None, variants,
- ReprOptions::new(&ccx.tcx, did));
- if let Some(ctor_id) = ctor_id {
- // Make adt definition available through constructor id as well.
- ccx.tcx.adt_defs.borrow_mut().insert(ctor_id, adt);
- }
+fn adt_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> &'tcx ty::AdtDef {
+ use rustc::hir::map::*;
+ use rustc::hir::*;
- ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
- adt
-}
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let item = match tcx.hir.get(node_id) {
+ NodeItem(item) => item,
-fn convert_union_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- it: &hir::Item,
- def: &hir::VariantData)
- -> &'tcx ty::AdtDef
-{
- let did = ccx.tcx.hir.local_def_id(it.id);
- let variants = vec![convert_struct_variant(ccx, did, it.name, 0, def)];
- let adt = ccx.tcx.alloc_adt_def(did, AdtKind::Union, None, variants,
- ReprOptions::new(&ccx.tcx, did));
- ccx.tcx.adt_defs.borrow_mut().insert(did, adt);
- adt
-}
+ // Make adt definition available through constructor id as well.
+ NodeStructCtor(_) => {
+ return tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id));
+ }
-fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, body: hir::BodyId)
- -> Option<ConstInt> {
- let e = &ccx.tcx.hir.body(body).value;
- debug!("disr expr, checking {}", ccx.tcx.hir.node_to_pretty_string(e.id));
-
- let ty_hint = repr_ty.to_ty(ccx.tcx);
- let print_err = |cv: ConstVal| {
- struct_span_err!(ccx.tcx.sess, e.span, E0079, "mismatched types")
- .note_expected_found(&"type", &ty_hint, &format!("{}", cv.description()))
- .span_label(e.span, &format!("expected '{}' type", ty_hint))
- .emit();
+ _ => bug!()
};
- let hint = UncheckedExprHint(ty_hint);
- match ConstContext::new(ccx.tcx, body).eval(e, hint) {
- Ok(ConstVal::Integral(i)) => {
- // FIXME: eval should return an error if the hint does not match the type of the body.
- // i.e. eventually the match below would not exist.
- match (repr_ty, i) {
- (attr::SignedInt(ast::IntTy::I8), ConstInt::I8(_)) |
- (attr::SignedInt(ast::IntTy::I16), ConstInt::I16(_)) |
- (attr::SignedInt(ast::IntTy::I32), ConstInt::I32(_)) |
- (attr::SignedInt(ast::IntTy::I64), ConstInt::I64(_)) |
- (attr::SignedInt(ast::IntTy::I128), ConstInt::I128(_)) |
- (attr::SignedInt(ast::IntTy::Is), ConstInt::Isize(_)) |
- (attr::UnsignedInt(ast::UintTy::U8), ConstInt::U8(_)) |
- (attr::UnsignedInt(ast::UintTy::U16), ConstInt::U16(_)) |
- (attr::UnsignedInt(ast::UintTy::U32), ConstInt::U32(_)) |
- (attr::UnsignedInt(ast::UintTy::U64), ConstInt::U64(_)) |
- (attr::UnsignedInt(ast::UintTy::U128), ConstInt::U128(_)) |
- (attr::UnsignedInt(ast::UintTy::Us), ConstInt::Usize(_)) =>
- Some(i),
- (_, i) => {
- print_err(ConstVal::Integral(i));
- None
- },
- }
- },
- Ok(cv) => {
- print_err(cv);
- None
- },
- // enum variant evaluation happens before the global constant check
- // so we need to report the real error
- Err(err) => {
- let mut diag = report_const_eval_err(
- ccx.tcx, &err, e.span, "enum discriminant");
- diag.emit();
- None
+ let repr = ReprOptions::new(tcx, def_id);
+ let (kind, variants) = match item.node {
+ ItemEnum(ref def, _) => {
+ let mut distance_from_explicit = 0;
+ (AdtKind::Enum, def.variants.iter().map(|v| {
+ let did = tcx.hir.local_def_id(v.node.data.id());
+ let discr = if let Some(e) = v.node.disr_expr {
+ distance_from_explicit = 0;
+ ty::VariantDiscr::Explicit(tcx.hir.local_def_id(e.node_id))
+ } else {
+ ty::VariantDiscr::Relative(distance_from_explicit)
+ };
+ distance_from_explicit += 1;
+
+ convert_struct_variant(tcx, did, v.node.name, discr, &v.node.data)
+ }).collect())
}
- }
-}
-
-fn convert_enum_def<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- it: &hir::Item,
- def: &hir::EnumDef)
- -> &'tcx ty::AdtDef
-{
- let tcx = ccx.tcx;
- let did = tcx.hir.local_def_id(it.id);
- let repr_hints = tcx.lookup_repr_hints(did);
- let repr_type = tcx.enum_repr_type(repr_hints.get(0));
- let initial = ConstInt::new_inttype(repr_type.initial_discriminant(tcx), repr_type,
- tcx.sess.target.uint_type, tcx.sess.target.int_type)
- .unwrap();
- let mut prev_disr = None::<ConstInt>;
- let variants = def.variants.iter().map(|v| {
- let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
- let disr = if let Some(e) = v.node.disr_expr {
- // FIXME: i128 discriminants
- evaluate_disr_expr(ccx, repr_type, e)
- } else if let Some(disr) = prev_disr.map_or(Some(initial),
- |v| (v + ConstInt::Infer(1)).ok()) {
- Some(disr)
- } else {
- struct_span_err!(tcx.sess, v.span, E0370,
- "enum discriminant overflowed")
- .span_label(v.span, &format!("overflowed on value after {}", prev_disr.unwrap()))
- .note(&format!("explicitly set `{} = {}` if that is desired outcome",
- v.node.name, wrapped_disr))
- .emit();
- None
- }.unwrap_or(wrapped_disr);
- prev_disr = Some(disr);
- let did = tcx.hir.local_def_id(v.node.data.id());
- convert_struct_variant(ccx, did, v.node.name, disr.to_u128_unchecked(), &v.node.data)
- }).collect();
- let adt = tcx.alloc_adt_def(did, AdtKind::Enum, Some(repr_type), variants,
- ReprOptions::new(&ccx.tcx, did));
- tcx.adt_defs.borrow_mut().insert(did, adt);
- adt
+ ItemStruct(ref def, _) => {
+ // Use separate constructor id for unit/tuple structs and reuse did for braced structs.
+ let ctor_id = if !def.is_struct() {
+ Some(tcx.hir.local_def_id(def.id()))
+ } else {
+ None
+ };
+ (AdtKind::Struct, vec![
+ convert_struct_variant(tcx, ctor_id.unwrap_or(def_id), item.name,
+ ty::VariantDiscr::Relative(0), def)
+ ])
+ }
+ ItemUnion(ref def, _) => {
+ (AdtKind::Union, vec![
+ convert_struct_variant(tcx, def_id, item.name,
+ ty::VariantDiscr::Relative(0), def)
+ ])
+ }
+ _ => bug!()
+ };
+ tcx.alloc_adt_def(def_id, kind, variants, repr)
}
/// Ensures that the super-predicates of the trait with def-id
-/// trait_def_id are converted and stored. This does NOT ensure that
-/// the transitive super-predicates are converted; that is the job of
-/// the `ensure_super_predicates()` method in the `AstConv` impl
-/// above. Returns a list of trait def-ids that must be ensured as
-/// well to guarantee that the transitive superpredicates are
-/// converted.
-fn ensure_super_predicates_step(ccx: &CrateCtxt,
- trait_def_id: DefId)
- -> Vec<DefId>
-{
- let tcx = ccx.tcx;
-
- debug!("ensure_super_predicates_step(trait_def_id={:?})", trait_def_id);
+/// trait_def_id are converted and stored. This also ensures that
+/// the transitive super-predicates are converted;
+fn super_predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ trait_def_id: DefId)
+ -> ty::GenericPredicates<'tcx> {
+ debug!("super_predicates(trait_def_id={:?})", trait_def_id);
+ let trait_node_id = tcx.hir.as_local_node_id(trait_def_id).unwrap();
+
+ let item = match tcx.hir.get(trait_node_id) {
+ hir_map::NodeItem(item) => item,
+ _ => bug!("trait_node_id {} is not an item", trait_node_id)
+ };
- let trait_node_id = if let Some(n) = tcx.hir.as_local_node_id(trait_def_id) {
- n
- } else {
- // If this trait comes from an external crate, then all of the
- // supertraits it may depend on also must come from external
- // crates, and hence all of them already have their
- // super-predicates "converted" (and available from crate
- // meta-data), so there is no need to transitively test them.
- return Vec::new();
+ let (generics, bounds) = match item.node {
+ hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
+ _ => span_bug!(item.span,
+ "super_predicates invoked on non-trait"),
};
- let superpredicates = tcx.super_predicates.borrow().get(&trait_def_id).cloned();
- let superpredicates = superpredicates.unwrap_or_else(|| {
- let item = match ccx.tcx.hir.get(trait_node_id) {
- hir_map::NodeItem(item) => item,
- _ => bug!("trait_node_id {} is not an item", trait_node_id)
- };
+ let icx = ItemCtxt::new(tcx, trait_def_id);
- let (generics, bounds) = match item.node {
- hir::ItemTrait(_, ref generics, ref supertraits, _) => (generics, supertraits),
- _ => span_bug!(item.span,
- "ensure_super_predicates_step invoked on non-trait"),
- };
+ // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
+ let self_param_ty = tcx.mk_self_type();
+ let superbounds1 = compute_bounds(&icx,
+ self_param_ty,
+ bounds,
+ SizedByDefault::No,
+ item.span);
- // In-scope when converting the superbounds for `Trait` are
- // that `Self:Trait` as well as any bounds that appear on the
- // generic types:
- generics_of_def_id(ccx, trait_def_id);
- trait_def_of_item(ccx, item);
- let trait_ref = ty::TraitRef {
- def_id: trait_def_id,
- substs: Substs::identity_for_item(tcx, trait_def_id)
- };
- let self_predicate = ty::GenericPredicates {
- parent: None,
- predicates: vec![trait_ref.to_predicate()]
- };
- let scope = &(generics, &self_predicate);
-
- // Convert the bounds that follow the colon, e.g. `Bar+Zed` in `trait Foo : Bar+Zed`.
- let self_param_ty = tcx.mk_self_type();
- let superbounds1 = compute_bounds(&ccx.icx(scope),
- self_param_ty,
- bounds,
- SizedByDefault::No,
- item.span);
-
- let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
-
- // Convert any explicit superbounds in the where clause,
- // e.g. `trait Foo where Self : Bar`:
- let superbounds2 = generics.get_type_parameter_bounds(&ccx.icx(scope), item.span, item.id);
-
- // Combine the two lists to form the complete set of superbounds:
- let superbounds = superbounds1.into_iter().chain(superbounds2).collect();
- let superpredicates = ty::GenericPredicates {
- parent: None,
- predicates: superbounds
- };
- debug!("superpredicates for trait {:?} = {:?}",
- tcx.hir.local_def_id(item.id),
- superpredicates);
+ let superbounds1 = superbounds1.predicates(tcx, self_param_ty);
- tcx.super_predicates.borrow_mut().insert(trait_def_id, superpredicates.clone());
+ // Convert any explicit superbounds in the where clause,
+ // e.g. `trait Foo where Self : Bar`:
+ let superbounds2 = icx.type_parameter_bounds_in_generics(generics, item.id, self_param_ty);
- superpredicates
- });
+ // Combine the two lists to form the complete set of superbounds:
+ let superbounds: Vec<_> = superbounds1.into_iter().chain(superbounds2).collect();
+
+ // Now require that immediate supertraits are converted,
+ // which will, in turn, reach indirect supertraits.
+ for bound in superbounds.iter().filter_map(|p| p.to_opt_poly_trait_ref()) {
+ ty::queries::super_predicates::get(tcx, item.span, bound.def_id());
+ }
+
+ ty::GenericPredicates {
+ parent: None,
+ predicates: superbounds
+ }
+}
+
+fn trait_def<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> &'tcx ty::TraitDef {
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let item = tcx.hir.expect_item(node_id);
+
+ let unsafety = match item.node {
+ hir::ItemTrait(unsafety, ..) => unsafety,
+ _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
+ };
+
+ let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar");
+ if paren_sugar && !tcx.sess.features.borrow().unboxed_closures {
+ let mut err = tcx.sess.struct_span_err(
+ item.span,
+ "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
+ which traits can use parenthetical notation");
+ help!(&mut err,
+ "add `#![feature(unboxed_closures)]` to \
+ the crate attributes to use it");
+ err.emit();
+ }
- let def_ids: Vec<_> = superpredicates.predicates
- .iter()
- .filter_map(|p| p.to_opt_poly_trait_ref())
- .map(|tr| tr.def_id())
- .collect();
+ let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
+ let def = ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash);
- debug!("ensure_super_predicates_step: def_ids={:?}", def_ids);
+ if tcx.hir.trait_is_auto(def_id) {
+ def.record_has_default_impl();
+ }
- def_ids
+ tcx.alloc_trait_def(def)
}
-fn trait_def_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) -> &'tcx ty::TraitDef {
- let def_id = ccx.tcx.hir.local_def_id(it.id);
- let tcx = ccx.tcx;
+fn generics<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> &'tcx ty::Generics {
+ use rustc::hir::map::*;
+ use rustc::hir::*;
+
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+
+ let node = tcx.hir.get(node_id);
+ let parent_def_id = match node {
+ NodeImplItem(_) |
+ NodeTraitItem(_) |
+ NodeVariant(_) |
+ NodeStructCtor(_) |
+ NodeField(_) => {
+ let parent_id = tcx.hir.get_parent(node_id);
+ Some(tcx.hir.local_def_id(parent_id))
+ }
+ NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+ Some(tcx.closure_base_def_id(def_id))
+ }
+ NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
+ let mut parent_id = node_id;
+ loop {
+ match tcx.hir.get(parent_id) {
+ NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break,
+ _ => {
+ parent_id = tcx.hir.get_parent_node(parent_id);
+ }
+ }
+ }
+ Some(tcx.hir.local_def_id(parent_id))
+ }
+ _ => None
+ };
- tcx.trait_defs.memoize(def_id, || {
- let unsafety = match it.node {
- hir::ItemTrait(unsafety, ..) => unsafety,
- _ => span_bug!(it.span, "trait_def_of_item invoked on non-trait"),
- };
+ let mut opt_self = None;
+ let mut allow_defaults = false;
- let paren_sugar = tcx.has_attr(def_id, "rustc_paren_sugar");
- if paren_sugar && !ccx.tcx.sess.features.borrow().unboxed_closures {
- let mut err = ccx.tcx.sess.struct_span_err(
- it.span,
- "the `#[rustc_paren_sugar]` attribute is a temporary means of controlling \
- which traits can use parenthetical notation");
- help!(&mut err,
- "add `#![feature(unboxed_closures)]` to \
- the crate attributes to use it");
- err.emit();
+ let no_generics = hir::Generics::empty();
+ let ast_generics = match node {
+ NodeTraitItem(item) => {
+ match item.node {
+ TraitItemKind::Method(ref sig, _) => &sig.generics,
+ _ => &no_generics
+ }
}
- let def_path_hash = tcx.def_path(def_id).deterministic_hash(tcx);
- tcx.alloc_trait_def(ty::TraitDef::new(def_id, unsafety, paren_sugar, def_path_hash))
- })
-}
+ NodeImplItem(item) => {
+ match item.node {
+ ImplItemKind::Method(ref sig, _) => &sig.generics,
+ _ => &no_generics
+ }
+ }
-fn convert_trait_predicates<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, it: &hir::Item) {
- let tcx = ccx.tcx;
+ NodeItem(item) => {
+ match item.node {
+ ItemFn(.., ref generics, _) |
+ ItemImpl(_, _, ref generics, ..) => generics,
+
+ ItemTy(_, ref generics) |
+ ItemEnum(_, ref generics) |
+ ItemStruct(_, ref generics) |
+ ItemUnion(_, ref generics) => {
+ allow_defaults = true;
+ generics
+ }
- let def_id = ccx.tcx.hir.local_def_id(it.id);
+ ItemTrait(_, ref generics, ..) => {
+ // Add in the self type parameter.
+ //
+ // Something of a hack: use the node id for the trait, also as
+ // the node id for the Self type parameter.
+ let param_id = item.id;
+
+ opt_self = Some(ty::TypeParameterDef {
+ index: 0,
+ name: keywords::SelfType.name(),
+ def_id: tcx.hir.local_def_id(param_id),
+ has_default: false,
+ object_lifetime_default: rl::Set1::Empty,
+ pure_wrt_drop: false,
+ });
+
+ allow_defaults = true;
+ generics
+ }
- generics_of_def_id(ccx, def_id);
- trait_def_of_item(ccx, it);
+ _ => &no_generics
+ }
+ }
- let (generics, items) = match it.node {
- hir::ItemTrait(_, ref generics, _, ref items) => (generics, items),
- ref s => {
- span_bug!(
- it.span,
- "trait_def_of_item invoked on {:?}",
- s);
+ NodeForeignItem(item) => {
+ match item.node {
+ ForeignItemStatic(..) => &no_generics,
+ ForeignItemFn(_, _, ref generics) => generics
+ }
}
+
+ _ => &no_generics
};
- let super_predicates = ccx.tcx.item_super_predicates(def_id);
+ let has_self = opt_self.is_some();
+ let mut parent_has_self = false;
+ let mut own_start = has_self as u32;
+ let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
+ let generics = tcx.item_generics(def_id);
+ assert_eq!(has_self, false);
+ parent_has_self = generics.has_self;
+ own_start = generics.count() as u32;
+ (generics.parent_regions + generics.regions.len() as u32,
+ generics.parent_types + generics.types.len() as u32)
+ });
- // `ty_generic_predicates` below will consider the bounds on the type
- // parameters (including `Self`) and the explicit where-clauses,
- // but to get the full set of predicates on a trait we need to add
- // in the supertrait bounds and anything declared on the
- // associated types.
- let mut base_predicates = super_predicates.predicates;
+ let early_lifetimes = early_bound_lifetimes_from_generics(tcx, ast_generics);
+ let regions = early_lifetimes.enumerate().map(|(i, l)| {
+ let issue_32330 = tcx.named_region_map.issue_32330.get(&l.lifetime.id).cloned();
+ ty::RegionParameterDef {
+ name: l.lifetime.name,
+ index: own_start + i as u32,
+ def_id: tcx.hir.local_def_id(l.lifetime.id),
+ pure_wrt_drop: l.pure_wrt_drop,
+ issue_32330: issue_32330,
+ }
+ }).collect::<Vec<_>>();
- // Add in a predicate that `Self:Trait` (where `Trait` is the
- // current trait). This is needed for builtin bounds.
- let trait_ref = ty::TraitRef {
- def_id: def_id,
- substs: Substs::identity_for_item(tcx, def_id)
- };
- let self_predicate = trait_ref.to_poly_trait_ref().to_predicate();
- base_predicates.push(self_predicate);
-
- // add in the explicit where-clauses
- let mut trait_predicates =
- ty_generic_predicates(ccx, generics, None, base_predicates, true);
-
- let assoc_predicates = predicates_for_associated_types(ccx,
- generics,
- &trait_predicates,
- trait_ref,
- items);
- trait_predicates.predicates.extend(assoc_predicates);
-
- tcx.predicates.borrow_mut().insert(def_id, trait_predicates);
- return;
-
- fn predicates_for_associated_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- ast_generics: &hir::Generics,
- trait_predicates: &ty::GenericPredicates<'tcx>,
- self_trait_ref: ty::TraitRef<'tcx>,
- trait_item_refs: &[hir::TraitItemRef])
- -> Vec<ty::Predicate<'tcx>>
- {
- trait_item_refs.iter().flat_map(|trait_item_ref| {
- let trait_item = ccx.tcx.hir.trait_item(trait_item_ref.id);
- let bounds = match trait_item.node {
- hir::TraitItemKind::Type(ref bounds, _) => bounds,
- _ => {
- return vec![].into_iter();
- }
- };
+ let object_lifetime_defaults =
+ tcx.named_region_map.object_lifetime_defaults.get(&node_id);
- let assoc_ty = ccx.tcx.mk_projection(self_trait_ref,
- trait_item.name);
+ // Now create the real type parameters.
+ let type_start = own_start + regions.len() as u32;
+ let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| {
+ if p.name == keywords::SelfType.name() {
+ span_bug!(p.span, "`Self` should not be the name of a regular parameter");
+ }
- let bounds = compute_bounds(&ccx.icx(&(ast_generics, trait_predicates)),
- assoc_ty,
- bounds,
- SizedByDefault::Yes,
- trait_item.span);
+ if !allow_defaults && p.default.is_some() {
+ if !tcx.sess.features.borrow().default_type_parameter_fallback {
+ tcx.sess.add_lint(
+ lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
+ p.id,
+ p.span,
+ format!("defaults for type parameters are only allowed in `struct`, \
+ `enum`, `type`, or `trait` definitions."));
+ }
+ }
- bounds.predicates(ccx.tcx, assoc_ty).into_iter()
- }).collect()
+ ty::TypeParameterDef {
+ index: type_start + i as u32,
+ name: p.name,
+ def_id: tcx.hir.local_def_id(p.id),
+ has_default: p.default.is_some(),
+ object_lifetime_default:
+ object_lifetime_defaults.map_or(rl::Set1::Empty, |o| o[i]),
+ pure_wrt_drop: p.pure_wrt_drop,
+ }
+ });
+ let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
+
+ // provide junk type parameter defs - the only place that
+ // cares about anything but the length is instantiation,
+ // and we don't do that for closures.
+ if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
+ tcx.with_freevars(node_id, |fv| {
+ types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
+ index: type_start + i as u32,
+ name: Symbol::intern("<upvar>"),
+ def_id: def_id,
+ has_default: false,
+ object_lifetime_default: rl::Set1::Empty,
+ pure_wrt_drop: false,
+ }));
+ });
}
+
+ let mut type_param_to_index = BTreeMap::new();
+ for param in &types {
+ type_param_to_index.insert(param.def_id.index, param.index);
+ }
+
+ tcx.alloc_generics(ty::Generics {
+ parent: parent_def_id,
+ parent_regions: parent_regions,
+ parent_types: parent_types,
+ regions: regions,
+ types: types,
+ type_param_to_index: type_param_to_index,
+ has_self: has_self || parent_has_self
+ })
}
-fn generics_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- def_id: DefId)
- -> &'tcx ty::Generics<'tcx> {
- let tcx = ccx.tcx;
- let node_id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
- id
- } else {
- return tcx.item_generics(def_id);
- };
- tcx.generics.memoize(def_id, || {
- use rustc::hir::map::*;
- use rustc::hir::*;
-
- let node = tcx.hir.get(node_id);
- let parent_def_id = match node {
- NodeImplItem(_) |
- NodeTraitItem(_) |
- NodeVariant(_) |
- NodeStructCtor(_) => {
- let parent_id = tcx.hir.get_parent(node_id);
- Some(tcx.hir.local_def_id(parent_id))
- }
- NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
- Some(tcx.closure_base_def_id(def_id))
- }
- NodeTy(&hir::Ty { node: hir::TyImplTrait(..), .. }) => {
- let mut parent_id = node_id;
- loop {
- match tcx.hir.get(parent_id) {
- NodeItem(_) | NodeImplItem(_) | NodeTraitItem(_) => break,
- _ => {
- parent_id = tcx.hir.get_parent_node(parent_id);
- }
- }
- }
- Some(tcx.hir.local_def_id(parent_id))
- }
- _ => None
- };
+fn ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> Ty<'tcx> {
+ use rustc::hir::map::*;
+ use rustc::hir::*;
- let mut opt_self = None;
- let mut allow_defaults = false;
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
- let no_generics = hir::Generics::empty();
- let ast_generics = match node {
- NodeTraitItem(item) => {
- match item.node {
- TraitItemKind::Method(ref sig, _) => &sig.generics,
- _ => &no_generics
- }
- }
+ let icx = ItemCtxt::new(tcx, def_id);
- NodeImplItem(item) => {
- match item.node {
- ImplItemKind::Method(ref sig, _) => &sig.generics,
- _ => &no_generics
+ match tcx.hir.get(node_id) {
+ NodeTraitItem(item) => {
+ match item.node {
+ TraitItemKind::Method(ref sig, _) => {
+ let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+ let substs = Substs::identity_for_item(tcx, def_id);
+ tcx.mk_fn_def(def_id, substs, fty)
+ }
+ TraitItemKind::Const(ref ty, _) |
+ TraitItemKind::Type(_, Some(ref ty)) => icx.to_ty(ty),
+ TraitItemKind::Type(_, None) => {
+ span_bug!(item.span, "associated type missing default");
}
}
+ }
- NodeItem(item) => {
- match item.node {
- ItemFn(.., ref generics, _) |
- ItemImpl(_, _, ref generics, ..) => generics,
-
- ItemTy(_, ref generics) |
- ItemEnum(_, ref generics) |
- ItemStruct(_, ref generics) |
- ItemUnion(_, ref generics) => {
- allow_defaults = true;
- generics
- }
-
- ItemTrait(_, ref generics, ..) => {
- // Add in the self type parameter.
- //
- // Something of a hack: use the node id for the trait, also as
- // the node id for the Self type parameter.
- let param_id = item.id;
-
- let parent = ccx.tcx.hir.get_parent(param_id);
-
- let def = ty::TypeParameterDef {
- index: 0,
- name: keywords::SelfType.name(),
- def_id: tcx.hir.local_def_id(param_id),
- default_def_id: tcx.hir.local_def_id(parent),
- default: None,
- pure_wrt_drop: false,
- };
- tcx.ty_param_defs.borrow_mut().insert(param_id, def.clone());
- opt_self = Some(def);
-
- allow_defaults = true;
- generics
+ NodeImplItem(item) => {
+ match item.node {
+ ImplItemKind::Method(ref sig, _) => {
+ let fty = AstConv::ty_of_fn(&icx, sig.unsafety, sig.abi, &sig.decl);
+ let substs = Substs::identity_for_item(tcx, def_id);
+ tcx.mk_fn_def(def_id, substs, fty)
+ }
+ ImplItemKind::Const(ref ty, _) => icx.to_ty(ty),
+ ImplItemKind::Type(ref ty) => {
+ if tcx.impl_trait_ref(tcx.hir.get_parent_did(node_id)).is_none() {
+ span_err!(tcx.sess, item.span, E0202,
+ "associated types are not allowed in inherent impls");
}
- _ => &no_generics
+ icx.to_ty(ty)
}
}
+ }
- NodeForeignItem(item) => {
- match item.node {
- ForeignItemStatic(..) => &no_generics,
- ForeignItemFn(_, _, ref generics) => generics
+ NodeItem(item) => {
+ match item.node {
+ ItemStatic(ref t, ..) | ItemConst(ref t, _) |
+ ItemTy(ref t, _) | ItemImpl(.., ref t, _) => {
+ icx.to_ty(t)
+ }
+ ItemFn(ref decl, unsafety, _, abi, _, _) => {
+ let tofd = AstConv::ty_of_fn(&icx, unsafety, abi, &decl);
+ let substs = Substs::identity_for_item(tcx, def_id);
+ tcx.mk_fn_def(def_id, substs, tofd)
+ }
+ ItemEnum(..) |
+ ItemStruct(..) |
+ ItemUnion(..) => {
+ let def = tcx.lookup_adt_def(def_id);
+ let substs = Substs::identity_for_item(tcx, def_id);
+ tcx.mk_adt(def, substs)
+ }
+ ItemDefaultImpl(..) |
+ ItemTrait(..) |
+ ItemMod(..) |
+ ItemForeignMod(..) |
+ ItemExternCrate(..) |
+ ItemUse(..) => {
+ span_bug!(
+ item.span,
+ "compute_type_of_item: unexpected item type: {:?}",
+ item.node);
}
}
+ }
- _ => &no_generics
- };
+ NodeForeignItem(foreign_item) => {
+ let abi = tcx.hir.get_foreign_abi(node_id);
- let has_self = opt_self.is_some();
- let mut parent_has_self = false;
- let mut own_start = has_self as u32;
- let (parent_regions, parent_types) = parent_def_id.map_or((0, 0), |def_id| {
- let generics = generics_of_def_id(ccx, def_id);
- assert_eq!(has_self, false);
- parent_has_self = generics.has_self;
- own_start = generics.count() as u32;
- (generics.parent_regions + generics.regions.len() as u32,
- generics.parent_types + generics.types.len() as u32)
- });
+ match foreign_item.node {
+ ForeignItemFn(ref fn_decl, _, _) => {
+ compute_type_of_foreign_fn_decl(tcx, def_id, fn_decl, abi)
+ }
+ ForeignItemStatic(ref t, _) => icx.to_ty(t)
+ }
+ }
- let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
- let regions = early_lifetimes.iter().enumerate().map(|(i, l)| {
- let issue_32330 = ccx.tcx.named_region_map.issue_32330
- .get(&l.lifetime.id)
- .cloned();
- ty::RegionParameterDef {
- name: l.lifetime.name,
- index: own_start + i as u32,
- def_id: tcx.hir.local_def_id(l.lifetime.id),
- pure_wrt_drop: l.pure_wrt_drop,
- issue_32330: issue_32330,
+ NodeStructCtor(&ref def) |
+ NodeVariant(&Spanned { node: hir::Variant_ { data: ref def, .. }, .. }) => {
+ let ty = tcx.item_type(tcx.hir.get_parent_did(node_id));
+ match *def {
+ VariantData::Unit(..) | VariantData::Struct(..) => ty,
+ VariantData::Tuple(ref fields, _) => {
+ let inputs = fields.iter().map(|f| {
+ tcx.item_type(tcx.hir.local_def_id(f.id))
+ });
+ let substs = Substs::identity_for_item(tcx, def_id);
+ tcx.mk_fn_def(def_id, substs, ty::Binder(tcx.mk_fn_sig(
+ inputs,
+ ty,
+ false,
+ hir::Unsafety::Normal,
+ abi::Abi::Rust
+ )))
+ }
}
- }).collect::<Vec<_>>();
+ }
- // Now create the real type parameters.
- let type_start = own_start + regions.len() as u32;
- let types = ast_generics.ty_params.iter().enumerate().map(|(i, p)| {
- let i = type_start + i as u32;
- get_or_create_type_parameter_def(ccx, i, p, allow_defaults)
- });
- let mut types: Vec<_> = opt_self.into_iter().chain(types).collect();
-
- // provide junk type parameter defs - the only place that
- // cares about anything but the length is instantiation,
- // and we don't do that for closures.
- if let NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) = node {
- tcx.with_freevars(node_id, |fv| {
- types.extend(fv.iter().enumerate().map(|(i, _)| ty::TypeParameterDef {
- index: type_start + i as u32,
- name: Symbol::intern("<upvar>"),
- def_id: def_id,
- default_def_id: parent_def_id.unwrap(),
- default: None,
- pure_wrt_drop: false,
- }));
- });
+ NodeField(field) => icx.to_ty(&field.ty),
+
+ NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
+ tcx.mk_closure(def_id, Substs::for_item(
+ tcx, def_id,
+ |def, _| {
+ let region = def.to_early_bound_region_data();
+ tcx.mk_region(ty::ReEarlyBound(region))
+ },
+ |def, _| tcx.mk_param_from_def(def)
+ ))
}
- tcx.alloc_generics(ty::Generics {
- parent: parent_def_id,
- parent_regions: parent_regions,
- parent_types: parent_types,
- regions: regions,
- types: types,
- has_self: has_self || parent_has_self
- })
- })
-}
+ NodeExpr(_) => match tcx.hir.get(tcx.hir.get_parent_node(node_id)) {
+ NodeTy(&hir::Ty { node: TyArray(_, body), .. }) |
+ NodeExpr(&hir::Expr { node: ExprRepeat(_, body), .. })
+ if body.node_id == node_id => tcx.types.usize,
-fn type_of_def_id<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- def_id: DefId)
- -> Ty<'tcx> {
- let node_id = if let Some(id) = ccx.tcx.hir.as_local_node_id(def_id) {
- id
- } else {
- return ccx.tcx.item_type(def_id);
- };
- ccx.tcx.item_types.memoize(def_id, || {
- use rustc::hir::map::*;
- use rustc::hir::*;
-
- // Alway bring in generics, as computing the type needs them.
- generics_of_def_id(ccx, def_id);
-
- let ty = match ccx.tcx.hir.get(node_id) {
- NodeItem(item) => {
- match item.node {
- ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
- ccx.icx(&()).to_ty(&t)
- }
- ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
- let tofd = AstConv::ty_of_fn(&ccx.icx(generics), unsafety, abi, &decl);
- let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
- ccx.tcx.mk_fn_def(def_id, substs, tofd)
- }
- ItemTy(ref t, ref generics) => {
- ccx.icx(generics).to_ty(&t)
- }
- ItemEnum(ref ei, ref generics) => {
- let def = convert_enum_def(ccx, item, ei);
- let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
- ccx.tcx.mk_adt(def, substs)
- }
- ItemStruct(ref si, ref generics) => {
- let def = convert_struct_def(ccx, item, si);
- let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
- ccx.tcx.mk_adt(def, substs)
- }
- ItemUnion(ref un, ref generics) => {
- let def = convert_union_def(ccx, item, un);
- let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
- ccx.tcx.mk_adt(def, substs)
- }
- ItemDefaultImpl(..) |
- ItemTrait(..) |
- ItemImpl(..) |
- ItemMod(..) |
- ItemForeignMod(..) |
- ItemExternCrate(..) |
- ItemUse(..) => {
- span_bug!(
- item.span,
- "compute_type_of_item: unexpected item type: {:?}",
- item.node);
- }
+ NodeVariant(&Spanned { node: Variant_ { disr_expr: Some(e), .. }, .. })
+ if e.node_id == node_id => {
+ tcx.lookup_adt_def(tcx.hir.get_parent_did(node_id))
+ .repr.discr_type().to_ty(tcx)
}
- }
- NodeForeignItem(foreign_item) => {
- let abi = ccx.tcx.hir.get_foreign_abi(node_id);
-
- match foreign_item.node {
- ForeignItemFn(ref fn_decl, _, ref generics) => {
- compute_type_of_foreign_fn_decl(
- ccx, ccx.tcx.hir.local_def_id(foreign_item.id),
- fn_decl, generics, abi)
- }
- ForeignItemStatic(ref t, _) => {
- ccx.icx(&()).to_ty(t)
- }
- }
- }
- NodeExpr(&hir::Expr { node: hir::ExprClosure(..), .. }) => {
- ccx.tcx.mk_closure(def_id, Substs::for_item(
- ccx.tcx, def_id,
- |def, _| {
- let region = def.to_early_bound_region_data();
- ccx.tcx.mk_region(ty::ReEarlyBound(region))
- },
- |def, _| ccx.tcx.mk_param_from_def(def)
- ))
- }
+
x => {
- bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
+ bug!("unexpected expr parent in type_of_def_id(): {:?}", x);
}
- };
-
- ty
- })
-}
-
-fn predicates_of_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- it: &hir::Item)
- -> ty::GenericPredicates<'tcx> {
- let def_id = ccx.tcx.hir.local_def_id(it.id);
+ },
- let no_generics = hir::Generics::empty();
- let generics = match it.node {
- hir::ItemFn(.., ref generics, _) |
- hir::ItemTy(_, ref generics) |
- hir::ItemEnum(_, ref generics) |
- hir::ItemStruct(_, ref generics) |
- hir::ItemUnion(_, ref generics) => generics,
- _ => &no_generics
- };
+ NodeTyParam(&hir::TyParam { default: Some(ref ty), .. }) => {
+ icx.to_ty(ty)
+ }
- let predicates = ty_generic_predicates(ccx, generics, None, vec![], false);
- ccx.tcx.predicates.borrow_mut().insert(def_id, predicates.clone());
+ NodeTy(&hir::Ty { node: TyImplTrait(..), .. }) => {
+ let owner = tcx.hir.get_parent_did(node_id);
+ tcx.item_tables(owner).node_id_to_type(node_id)
+ }
- predicates
+ x => {
+ bug!("unexpected sort of node in type_of_def_id(): {:?}", x);
+ }
+ }
}
-fn convert_foreign_item<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
- it: &hir::ForeignItem)
-{
- // For reasons I cannot fully articulate, I do so hate the AST
- // map, and I regard each time that I use it as a personal and
- // moral failing, but at the moment it seems like the only
- // convenient way to extract the ABI. - ndm
- let def_id = ccx.tcx.hir.local_def_id(it.id);
- type_of_def_id(ccx, def_id);
- generics_of_def_id(ccx, def_id);
-
- let no_generics = hir::Generics::empty();
- let generics = match it.node {
- hir::ForeignItemFn(_, _, ref generics) => generics,
- hir::ForeignItemStatic(..) => &no_generics
- };
+fn impl_trait_ref<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> Option<ty::TraitRef<'tcx>> {
+ let icx = ItemCtxt::new(tcx, def_id);
- let predicates = ty_generic_predicates(ccx, generics, None, vec![], false);
- ccx.tcx.predicates.borrow_mut().insert(def_id, predicates);
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ match tcx.hir.expect_item(node_id).node {
+ hir::ItemDefaultImpl(_, ref ast_trait_ref) => {
+ Some(AstConv::instantiate_mono_trait_ref(&icx,
+ ast_trait_ref,
+ tcx.mk_self_type()))
+ }
+ hir::ItemImpl(.., ref opt_trait_ref, _, _) => {
+ opt_trait_ref.as_ref().map(|ast_trait_ref| {
+ let selfty = tcx.item_type(def_id);
+ AstConv::instantiate_mono_trait_ref(&icx, ast_trait_ref, selfty)
+ })
+ }
+ _ => bug!()
+ }
}
// Is it marked with ?Sized
/// the lifetimes that are declared. For fns or methods, we have to
/// screen out those that do not appear in any where-clauses etc using
/// `resolve_lifetime::early_bound_lifetimes`.
-fn early_bound_lifetimes_from_generics<'a, 'tcx, 'hir>(
- ccx: &CrateCtxt<'a, 'tcx>,
- ast_generics: &'hir hir::Generics)
- -> Vec<&'hir hir::LifetimeDef>
+fn early_bound_lifetimes_from_generics<'a, 'tcx>(
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ ast_generics: &'a hir::Generics)
+ -> impl Iterator<Item=&'a hir::LifetimeDef>
{
ast_generics
.lifetimes
.iter()
- .filter(|l| !ccx.tcx.named_region_map.late_bound.contains(&l.lifetime.id))
- .collect()
+ .filter(move |l| !tcx.named_region_map.late_bound.contains(&l.lifetime.id))
}
-fn ty_generic_predicates<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
- ast_generics: &hir::Generics,
- parent: Option<DefId>,
- super_predicates: Vec<ty::Predicate<'tcx>>,
- has_self: bool)
- -> ty::GenericPredicates<'tcx>
-{
- let tcx = ccx.tcx;
- let parent_count = parent.map_or(0, |def_id| {
- let generics = generics_of_def_id(ccx, def_id);
- assert_eq!(generics.parent, None);
- assert_eq!(generics.parent_regions, 0);
- assert_eq!(generics.parent_types, 0);
- generics.count() as u32
- });
- let ref base_predicates = match parent {
- Some(def_id) => {
- assert_eq!(super_predicates, vec![]);
- tcx.item_predicates(def_id)
+fn predicates<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> ty::GenericPredicates<'tcx> {
+ use rustc::hir::map::*;
+ use rustc::hir::*;
+
+ let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
+ let node = tcx.hir.get(node_id);
+
+ let mut is_trait = None;
+
+ let icx = ItemCtxt::new(tcx, def_id);
+ let no_generics = hir::Generics::empty();
+ let ast_generics = match node {
+ NodeTraitItem(item) => {
+ match item.node {
+ TraitItemKind::Method(ref sig, _) => &sig.generics,
+ _ => &no_generics
+ }
}
- None => {
- ty::GenericPredicates {
- parent: None,
- predicates: super_predicates.clone()
+
+ NodeImplItem(item) => {
+ match item.node {
+ ImplItemKind::Method(ref sig, _) => &sig.generics,
+ _ => &no_generics
+ }
+ }
+
+ NodeItem(item) => {
+ match item.node {
+ ItemFn(.., ref generics, _) |
+ ItemImpl(_, _, ref generics, ..) |
+ ItemTy(_, ref generics) |
+ ItemEnum(_, ref generics) |
+ ItemStruct(_, ref generics) |
+ ItemUnion(_, ref generics) => {
+ generics
+ }
+
+ ItemTrait(_, ref generics, .., ref items) => {
+ is_trait = Some((ty::TraitRef {
+ def_id: def_id,
+ substs: Substs::identity_for_item(tcx, def_id)
+ }, items));
+ generics
+ }
+
+ _ => &no_generics
}
}
+
+ NodeForeignItem(item) => {
+ match item.node {
+ ForeignItemStatic(..) => &no_generics,
+ ForeignItemFn(_, _, ref generics) => generics
+ }
+ }
+
+ NodeTy(&Ty { node: TyImplTrait(ref bounds), span, .. }) => {
+ let substs = Substs::identity_for_item(tcx, def_id);
+ let anon_ty = tcx.mk_anon(def_id, substs);
+
+ // Collect the bounds, i.e. the `A+B+'c` in `impl A+B+'c`.
+ let bounds = compute_bounds(&icx, anon_ty, bounds,
+ SizedByDefault::Yes,
+ span);
+ return ty::GenericPredicates {
+ parent: None,
+ predicates: bounds.predicates(tcx, anon_ty)
+ };
+ }
+
+ _ => &no_generics
};
- let mut predicates = super_predicates;
+
+ let generics = tcx.item_generics(def_id);
+ let parent_count = generics.parent_count() as u32;
+ let has_own_self = generics.has_self && parent_count == 0;
+
+ let mut predicates = vec![];
+
+ // Below we'll consider the bounds on the type parameters (including `Self`)
+ // and the explicit where-clauses, but to get the full set of predicates
+ // on a trait we need to add in the supertrait bounds and bounds found on
+ // associated types.
+ if let Some((trait_ref, _)) = is_trait {
+ predicates = tcx.item_super_predicates(def_id).predicates;
+
+ // Add in a predicate that `Self:Trait` (where `Trait` is the
+ // current trait). This is needed for builtin bounds.
+ predicates.push(trait_ref.to_poly_trait_ref().to_predicate());
+ }
// Collect the region predicates that were declared inline as
// well. In the case of parameters declared on a fn or method, we
// have to be careful to only iterate over early-bound regions.
- let own_start = parent_count + has_self as u32;
- let early_lifetimes = early_bound_lifetimes_from_generics(ccx, ast_generics);
- for (index, param) in early_lifetimes.iter().enumerate() {
- let index = own_start + index as u32;
- let region = ccx.tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
+ let mut index = parent_count + has_own_self as u32;
+ for param in early_bound_lifetimes_from_generics(tcx, ast_generics) {
+ let region = tcx.mk_region(ty::ReEarlyBound(ty::EarlyBoundRegion {
index: index,
name: param.lifetime.name
}));
+ index += 1;
+
for bound in ¶m.bounds {
- let bound_region = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None);
+ let bound_region = AstConv::ast_region_to_region(&icx, bound, None);
let outlives = ty::Binder(ty::OutlivesPredicate(region, bound_region));
predicates.push(outlives.to_predicate());
}
// Collect the predicates that were written inline by the user on each
// type parameter (e.g., `<T:Foo>`).
- let type_start = own_start + early_lifetimes.len() as u32;
- for (index, param) in ast_generics.ty_params.iter().enumerate() {
- let index = type_start + index as u32;
- let param_ty = ty::ParamTy::new(index, param.name).to_ty(ccx.tcx);
- let bounds = compute_bounds(&ccx.icx(&(base_predicates, ast_generics)),
+ for param in &ast_generics.ty_params {
+ let param_ty = ty::ParamTy::new(index, param.name).to_ty(tcx);
+ index += 1;
+
+ let bounds = compute_bounds(&icx,
param_ty,
¶m.bounds,
SizedByDefault::Yes,
param.span);
- predicates.extend(bounds.predicates(ccx.tcx, param_ty));
+ predicates.extend(bounds.predicates(tcx, param_ty));
}
// Add in the bounds that appear in the where-clause
for predicate in &where_clause.predicates {
match predicate {
&hir::WherePredicate::BoundPredicate(ref bound_pred) => {
- let ty = AstConv::ast_ty_to_ty(&ccx.icx(&(base_predicates, ast_generics)),
- &bound_pred.bounded_ty);
+ let ty = icx.to_ty(&bound_pred.bounded_ty);
for bound in bound_pred.bounds.iter() {
match bound {
let mut projections = Vec::new();
let trait_ref =
- AstConv::instantiate_poly_trait_ref(&ccx.icx(&(base_predicates,
- ast_generics)),
+ AstConv::instantiate_poly_trait_ref(&icx,
poly_trait_ref,
ty,
&mut projections);
}
&hir::TyParamBound::RegionTyParamBound(ref lifetime) => {
- let region = AstConv::ast_region_to_region(&ccx.icx(&()),
+ let region = AstConv::ast_region_to_region(&icx,
lifetime,
None);
let pred = ty::Binder(ty::OutlivesPredicate(ty, region));
}
&hir::WherePredicate::RegionPredicate(ref region_pred) => {
- let r1 = AstConv::ast_region_to_region(&ccx.icx(&()), ®ion_pred.lifetime, None);
+ let r1 = AstConv::ast_region_to_region(&icx, ®ion_pred.lifetime, None);
for bound in ®ion_pred.bounds {
- let r2 = AstConv::ast_region_to_region(&ccx.icx(&()), bound, None);
+ let r2 = AstConv::ast_region_to_region(&icx, bound, None);
let pred = ty::Binder(ty::OutlivesPredicate(r1, r2));
predicates.push(ty::Predicate::RegionOutlives(pred))
}
}
}
- ty::GenericPredicates {
- parent: parent,
- predicates: predicates
- }
-}
-
-fn get_or_create_type_parameter_def<'a,'tcx>(ccx: &CrateCtxt<'a,'tcx>,
- index: u32,
- param: &hir::TyParam,
- allow_defaults: bool)
- -> ty::TypeParameterDef<'tcx>
-{
- let tcx = ccx.tcx;
- match tcx.ty_param_defs.borrow().get(¶m.id) {
- Some(d) => { return d.clone(); }
- None => { }
- }
+ // Add predicates from associated type bounds.
+ if let Some((self_trait_ref, trait_items)) = is_trait {
+ predicates.extend(trait_items.iter().flat_map(|trait_item_ref| {
+ let trait_item = tcx.hir.trait_item(trait_item_ref.id);
+ let bounds = match trait_item.node {
+ hir::TraitItemKind::Type(ref bounds, _) => bounds,
+ _ => {
+ return vec![].into_iter();
+ }
+ };
- let default =
- param.default.as_ref().map(|def| ccx.icx(&()).to_ty(def));
+ let assoc_ty = tcx.mk_projection(self_trait_ref, trait_item.name);
- let parent = tcx.hir.get_parent(param.id);
+ let bounds = compute_bounds(&ItemCtxt::new(tcx, def_id),
+ assoc_ty,
+ bounds,
+ SizedByDefault::Yes,
+ trait_item.span);
- if !allow_defaults && default.is_some() {
- if !tcx.sess.features.borrow().default_type_parameter_fallback {
- tcx.sess.add_lint(
- lint::builtin::INVALID_TYPE_PARAM_DEFAULT,
- param.id,
- param.span,
- format!("defaults for type parameters are only allowed in `struct`, \
- `enum`, `type`, or `trait` definitions."));
- }
+ bounds.predicates(tcx, assoc_ty).into_iter()
+ }))
}
- let def = ty::TypeParameterDef {
- index: index,
- name: param.name,
- def_id: ccx.tcx.hir.local_def_id(param.id),
- default_def_id: ccx.tcx.hir.local_def_id(parent),
- default: default,
- pure_wrt_drop: param.pure_wrt_drop,
- };
-
- if def.name == keywords::SelfType.name() {
- span_bug!(param.span, "`Self` should not be the name of a regular parameter");
+ // Subtle: before we store the predicates into the tcx, we
+ // sort them so that predicates like `T: Foo<Item=U>` come
+ // before uses of `U`. This avoids false ambiguity errors
+ // in trait checking. See `setup_constraining_predicates`
+ // for details.
+ if let NodeItem(&Item { node: ItemImpl(..), .. }) = node {
+ let self_ty = tcx.item_type(def_id);
+ let trait_ref = tcx.impl_trait_ref(def_id);
+ ctp::setup_constraining_predicates(&mut predicates,
+ trait_ref,
+ &mut ctp::parameters_for_impl(self_ty, trait_ref));
}
- tcx.ty_param_defs.borrow_mut().insert(param.id, def.clone());
-
- debug!("get_or_create_type_parameter_def: def for type param: {:?}", def);
-
- def
+ ty::GenericPredicates {
+ parent: generics.parent,
+ predicates: predicates
+ }
}
pub enum SizedByDefault { Yes, No, }
}
fn compute_type_of_foreign_fn_decl<'a, 'tcx>(
- ccx: &CrateCtxt<'a, 'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
def_id: DefId,
decl: &hir::FnDecl,
- ast_generics: &hir::Generics,
abi: abi::Abi)
-> Ty<'tcx>
{
- let fty = AstConv::ty_of_fn(&ccx.icx(ast_generics), hir::Unsafety::Unsafe, abi, decl);
+ let fty = AstConv::ty_of_fn(&ItemCtxt::new(tcx, def_id), hir::Unsafety::Unsafe, abi, decl);
// feature gate SIMD types in FFI, since I (huonw) am not sure the
// ABIs are handled at all correctly.
if abi != abi::Abi::RustIntrinsic && abi != abi::Abi::PlatformIntrinsic
- && !ccx.tcx.sess.features.borrow().simd_ffi {
+ && !tcx.sess.features.borrow().simd_ffi {
let check = |ast_ty: &hir::Ty, ty: ty::Ty| {
if ty.is_simd() {
- ccx.tcx.sess.struct_span_err(ast_ty.span,
+ tcx.sess.struct_span_err(ast_ty.span,
&format!("use of SIMD type `{}` in FFI is highly experimental and \
may result in invalid code",
- ccx.tcx.hir.node_to_pretty_string(ast_ty.id)))
+ tcx.hir.node_to_pretty_string(ast_ty.id)))
.help("add #![feature(simd_ffi)] to the crate attributes to enable")
.emit();
}
};
- for (input, ty) in decl.inputs.iter().zip(*fty.sig.inputs().skip_binder()) {
+ for (input, ty) in decl.inputs.iter().zip(*fty.inputs().skip_binder()) {
check(&input, ty)
}
if let hir::Return(ref ty) = decl.output {
- check(&ty, *fty.sig.output().skip_binder())
+ check(&ty, *fty.output().skip_binder())
}
}
- let id = ccx.tcx.hir.as_local_node_id(def_id).unwrap();
- let substs = mk_item_substs(&ccx.icx(ast_generics), ccx.tcx.hir.span(id), def_id);
- ccx.tcx.mk_fn_def(def_id, substs, fty)
-}
-
-fn mk_item_substs<'tcx>(astconv: &AstConv<'tcx, 'tcx>,
- span: Span,
- def_id: DefId)
- -> &'tcx Substs<'tcx> {
- let tcx = astconv.tcx();
- // FIXME(eddyb) Do this request from Substs::for_item in librustc.
- if let Err(ErrorReported) = astconv.get_generics(span, def_id) {
- // No convenient way to recover from a cycle here. Just bail. Sorry!
- tcx.sess.abort_if_errors();
- bug!("ErrorReported returned, but no errors reports?")
- }
-
- Substs::identity_for_item(tcx, def_id)
+ let substs = Substs::identity_for_item(tcx, def_id);
+ tcx.mk_fn_def(def_id, substs, fty)
}
```
"##,
-E0079: r##"
-Enum variants which contain no data can be given a custom integer
-representation. This error indicates that the value provided is not an integer
-literal and is therefore invalid.
-
-For example, in the following code:
-
-```compile_fail,E0079
-enum Foo {
- Q = "32",
-}
-```
-
-We try to set the representation to a string.
-
-There's no general fix for this; if you can work with an integer then just set
-it to one:
-
-```
-enum Foo {
- Q = 32,
-}
-```
-
-However if you actually wanted a mapping between variants and non-integer
-objects, it may be preferable to use a method with a match instead:
-
-```
-enum Foo { Q }
-impl Foo {
- fn get_str(&self) -> &'static str {
- match *self {
- Foo::Q => "32",
- }
- }
-}
-```
-"##,
-
E0081: r##"
Enum discriminants are used to differentiate enum variants stored in memory.
This error indicates that the same value was used for two or more variants,
```
"##,
+E0109: r##"
+You tried to give a type parameter to a type which doesn't need it. Erroneous
+code example:
+
+```compile_fail,E0109
+type X = u32<i32>; // error: type parameters are not allowed on this type
+```
+
+Please check that you used the correct type and recheck its definition. Perhaps
+it doesn't need the type parameter.
+
+Example:
+
+```
+type X = u32; // this compiles
+```
+
+Note that type parameters for enum-variant constructors go after the variant,
+not after the enum (Option::None::<u32>, not Option::<u32>::None).
+"##,
+
+E0110: r##"
+You tried to give a lifetime parameter to a type which doesn't need it.
+Erroneous code example:
+
+```compile_fail,E0110
+type X = u32<'static>; // error: lifetime parameters are not allowed on
+ // this type
+```
+
+Please check that the correct type was used and recheck its definition; perhaps
+it doesn't need the lifetime parameter. Example:
+
+```
+type X = u32; // ok!
+```
+"##,
+
E0116: r##"
You can only define an inherent implementation for a type in the same crate
where the type was defined. For example, an `impl` block as below is not allowed
```
"##,
-E0128: r##"
-Type parameter defaults can only use parameters that occur before them.
-Erroneous code example:
-
-```compile_fail,E0128
-struct Foo<T=U, U=()> {
- field1: T,
- filed2: U,
-}
-// error: type parameters with a default cannot use forward declared
-// identifiers
-```
-
-Since type parameters are evaluated in-order, you may be able to fix this issue
-by doing:
-
-```
-struct Foo<U=(), T=U> {
- field1: T,
- filed2: U,
-}
-```
-
-Please also verify that this wasn't because of a name-clash and rename the type
-parameter if so.
-"##,
-
E0131: r##"
It is not possible to define `main` with type parameters, or even with function
parameters. When `main` is present, it must take no arguments and return `()`.
```
"##,
+E0229: r##"
+An associated type binding was done outside of the type parameter declaration
+and `where` clause. Erroneous code example:
+
+```compile_fail,E0229
+pub trait Foo {
+ type A;
+ fn boo(&self) -> <Self as Foo>::A;
+}
+
+struct Bar;
+
+impl Foo for isize {
+ type A = usize;
+ fn boo(&self) -> usize { 42 }
+}
+
+fn baz<I>(x: &<I as Foo<A=Bar>>::A) {}
+// error: associated type bindings are not allowed here
+```
+
+To solve this error, please move the type bindings in the type parameter
+declaration:
+
+```ignore
+fn baz<I: Foo<A=Bar>>(x: &<I as Foo>::A) {} // ok!
+```
+
+Or in the `where` clause:
+
+```ignore
+fn baz<I>(x: &<I as Foo>::A) where I: Foo<A=Bar> {}
+```
+"##,
+
E0230: r##"
The trait has more type parameters specified than appear in its definition.
```
"##,
-E0391: r##"
-This error indicates that some types or traits depend on each other
-and therefore cannot be constructed.
-
-The following example contains a circular dependency between two traits:
-
-```compile_fail,E0391
-trait FirstTrait : SecondTrait {
-
-}
-
-trait SecondTrait : FirstTrait {
-
-}
-```
-"##,
-
E0392: r##"
This error indicates that a type or lifetime parameter has been declared
but not actually used. Here is an example that demonstrates the error:
use rustc::hir;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::def_id::DefId;
-use rustc::ty;
+use rustc::ty::{self, TyCtxt};
use rustc::util::nodemap::{FxHashMap, FxHashSet};
use std::collections::hash_map::Entry::{Occupied, Vacant};
use syntax_pos::Span;
-use CrateCtxt;
-
/// Checks that all the type/lifetime parameters on an impl also
/// appear in the trait ref or self-type (or are constrained by a
/// where-clause). These rules are needed to ensure that, given a
/// impl<'a> Trait<Foo> for Bar { type X = &'a i32; }
/// ^ 'a is unused and appears in assoc type, error
/// ```
-pub fn impl_wf_check<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>) {
+pub fn impl_wf_check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
// We will tag this as part of the WF check -- logically, it is,
// but it's one that we must perform earlier than the rest of
// WfCheck.
- ccx.tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { ccx: ccx });
+ tcx.visit_all_item_likes_in_krate(DepNode::WfCheck, &mut ImplWfCheck { tcx: tcx });
}
struct ImplWfCheck<'a, 'tcx: 'a> {
- ccx: &'a CrateCtxt<'a, 'tcx>,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for ImplWfCheck<'a, 'tcx> {
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
hir::ItemImpl(.., ref generics, _, _, ref impl_item_refs) => {
- let impl_def_id = self.ccx.tcx.hir.local_def_id(item.id);
- enforce_impl_params_are_constrained(self.ccx,
+ let impl_def_id = self.tcx.hir.local_def_id(item.id);
+ enforce_impl_params_are_constrained(self.tcx,
generics,
impl_def_id,
impl_item_refs);
- enforce_impl_items_are_distinct(self.ccx, impl_item_refs);
+ enforce_impl_items_are_distinct(self.tcx, impl_item_refs);
}
_ => { }
}
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
}
-fn enforce_impl_params_are_constrained<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn enforce_impl_params_are_constrained<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_hir_generics: &hir::Generics,
impl_def_id: DefId,
impl_item_refs: &[hir::ImplItemRef])
{
// Every lifetime used in an associated type must be constrained.
- let impl_self_ty = ccx.tcx.item_type(impl_def_id);
- let impl_generics = ccx.tcx.item_generics(impl_def_id);
- let impl_predicates = ccx.tcx.item_predicates(impl_def_id);
- let impl_trait_ref = ccx.tcx.impl_trait_ref(impl_def_id);
+ let impl_self_ty = tcx.item_type(impl_def_id);
+ let impl_generics = tcx.item_generics(impl_def_id);
+ let impl_predicates = tcx.item_predicates(impl_def_id);
+ let impl_trait_ref = tcx.impl_trait_ref(impl_def_id);
let mut input_parameters = ctp::parameters_for_impl(impl_self_ty, impl_trait_ref);
ctp::identify_constrained_type_params(
for (ty_param, param) in impl_generics.types.iter().zip(&impl_hir_generics.ty_params) {
let param_ty = ty::ParamTy::for_def(ty_param);
if !input_parameters.contains(&ctp::Parameter::from(param_ty)) {
- report_unused_parameter(ccx, param.span, "type", ¶m_ty.to_string());
+ report_unused_parameter(tcx, param.span, "type", ¶m_ty.to_string());
}
}
// Disallow unconstrained lifetimes, but only if they appear in assoc types.
let lifetimes_in_associated_types: FxHashSet<_> = impl_item_refs.iter()
- .map(|item_ref| ccx.tcx.hir.local_def_id(item_ref.id.node_id))
+ .map(|item_ref| tcx.hir.local_def_id(item_ref.id.node_id))
.filter(|&def_id| {
- let item = ccx.tcx.associated_item(def_id);
+ let item = tcx.associated_item(def_id);
item.kind == ty::AssociatedKind::Type && item.defaultness.has_value()
})
.flat_map(|def_id| {
- ctp::parameters_for(&ccx.tcx.item_type(def_id), true)
+ ctp::parameters_for(&tcx.item_type(def_id), true)
}).collect();
for (ty_lifetime, lifetime) in impl_generics.regions.iter()
.zip(&impl_hir_generics.lifetimes)
lifetimes_in_associated_types.contains(¶m) && // (*)
!input_parameters.contains(¶m)
{
- report_unused_parameter(ccx, lifetime.lifetime.span,
+ report_unused_parameter(tcx, lifetime.lifetime.span,
"lifetime", &lifetime.lifetime.name.to_string());
}
}
// used elsewhere are not projected back out.
}
-fn report_unused_parameter(ccx: &CrateCtxt,
+fn report_unused_parameter(tcx: TyCtxt,
span: Span,
kind: &str,
name: &str)
{
struct_span_err!(
- ccx.tcx.sess, span, E0207,
+ tcx.sess, span, E0207,
"the {} parameter `{}` is not constrained by the \
impl trait, self type, or predicates",
kind, name)
}
/// Enforce that we do not have two items in an impl with the same name.
-fn enforce_impl_items_are_distinct<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn enforce_impl_items_are_distinct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
impl_item_refs: &[hir::ImplItemRef])
{
- let tcx = ccx.tcx;
let mut seen_type_items = FxHashMap();
let mut seen_value_items = FxHashMap();
for impl_item_ref in impl_item_refs {
use rustc::infer::InferOk;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
+use rustc::ty::maps::Providers;
+use rustc::traits::{ObligationCause, ObligationCauseCode, Reveal};
use session::config;
use util::common::time;
use syntax_pos::Span;
use std::iter;
-use std::cell::RefCell;
-use util::nodemap::NodeMap;
-
// NB: This module needs to be declared first so diagnostics are
// registered before they are used.
pub mod diagnostics;
pub ty: Ty<'tcx>,
}
-pub struct CrateCtxt<'a, 'tcx: 'a> {
- ast_ty_to_ty_cache: RefCell<NodeMap<Ty<'tcx>>>,
-
- /// A vector of every trait accessible in the whole crate
- /// (i.e. including those from subcrates). This is used only for
- /// error reporting, and so is lazily initialised and generally
- /// shouldn't taint the common path (hence the RefCell).
- pub all_traits: RefCell<Option<check::method::AllTraitsVec>>,
-
- /// This stack is used to identify cycles in the user's source.
- /// Note that these cycles can cross multiple items.
- pub stack: RefCell<Vec<collect::AstConvRequest>>,
-
- pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
-
- /// Obligations which will have to be checked at the end of
- /// type-checking, after all functions have been inferred.
- /// The key is the NodeId of the item the obligations were from.
- pub deferred_obligations: RefCell<NodeMap<Vec<traits::DeferredObligation<'tcx>>>>,
-}
-
fn require_c_abi_if_variadic(tcx: TyCtxt,
decl: &hir::FnDecl,
abi: Abi,
}
}
-fn require_same_types<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
+fn require_same_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
cause: &ObligationCause<'tcx>,
expected: Ty<'tcx>,
actual: Ty<'tcx>)
-> bool {
- ccx.tcx.infer_ctxt((), Reveal::NotSpecializable).enter(|infcx| {
+ tcx.infer_ctxt((), Reveal::UserFacing).enter(|infcx| {
match infcx.eq_types(false, &cause, expected, actual) {
Ok(InferOk { obligations, .. }) => {
// FIXME(#32730) propagate obligations
})
}
-fn check_main_fn_ty(ccx: &CrateCtxt,
- main_id: ast::NodeId,
- main_span: Span) {
- let tcx = ccx.tcx;
+fn check_main_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ main_id: ast::NodeId,
+ main_span: Span) {
let main_def_id = tcx.hir.local_def_id(main_id);
let main_t = tcx.item_type(main_def_id);
match main_t.sty {
match it.node {
hir::ItemFn(.., ref generics, _) => {
if generics.is_parameterized() {
- struct_span_err!(ccx.tcx.sess, generics.span, E0131,
+ struct_span_err!(tcx.sess, generics.span, E0131,
"main function is not allowed to have type parameters")
.span_label(generics.span,
&format!("main cannot have type parameters"))
}
let substs = tcx.intern_substs(&[]);
let se_ty = tcx.mk_fn_def(main_def_id, substs,
- tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- sig: ty::Binder(tcx.mk_fn_sig(iter::empty(), tcx.mk_nil(), false))
- }));
+ ty::Binder(tcx.mk_fn_sig(
+ iter::empty(),
+ tcx.mk_nil(),
+ false,
+ hir::Unsafety::Normal,
+ Abi::Rust
+ ))
+ );
require_same_types(
- ccx,
+ tcx,
&ObligationCause::new(main_span, main_id, ObligationCauseCode::MainFunctionType),
se_ty,
main_t);
}
}
-fn check_start_fn_ty(ccx: &CrateCtxt,
- start_id: ast::NodeId,
- start_span: Span) {
- let tcx = ccx.tcx;
- let start_def_id = ccx.tcx.hir.local_def_id(start_id);
+fn check_start_fn_ty<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ start_id: ast::NodeId,
+ start_span: Span) {
+ let start_def_id = tcx.hir.local_def_id(start_id);
let start_t = tcx.item_type(start_def_id);
match start_t.sty {
ty::TyFnDef(..) => {
let substs = tcx.intern_substs(&[]);
let se_ty = tcx.mk_fn_def(start_def_id, substs,
- tcx.mk_bare_fn(ty::BareFnTy {
- unsafety: hir::Unsafety::Normal,
- abi: Abi::Rust,
- sig: ty::Binder(tcx.mk_fn_sig(
+ ty::Binder(tcx.mk_fn_sig(
[
tcx.types.isize,
tcx.mk_imm_ptr(tcx.mk_imm_ptr(tcx.types.u8))
].iter().cloned(),
tcx.types.isize,
false,
- )),
- }));
+ hir::Unsafety::Normal,
+ Abi::Rust
+ ))
+ );
require_same_types(
- ccx,
+ tcx,
&ObligationCause::new(start_span, start_id, ObligationCauseCode::StartFunctionType),
se_ty,
start_t);
}
}
-fn check_for_entry_fn(ccx: &CrateCtxt) {
- let tcx = ccx.tcx;
+fn check_for_entry_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
let _task = tcx.dep_graph.in_task(DepNode::CheckEntryFn);
if let Some((id, sp)) = *tcx.sess.entry_fn.borrow() {
match tcx.sess.entry_type.get() {
- Some(config::EntryMain) => check_main_fn_ty(ccx, id, sp),
- Some(config::EntryStart) => check_start_fn_ty(ccx, id, sp),
+ Some(config::EntryMain) => check_main_fn_ty(tcx, id, sp),
+ Some(config::EntryStart) => check_start_fn_ty(tcx, id, sp),
Some(config::EntryNone) => {}
None => bug!("entry function without a type")
}
}
}
+pub fn provide(providers: &mut Providers) {
+ collect::provide(providers);
+ coherence::provide(providers);
+ check::provide(providers);
+}
+
pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
- -> Result<NodeMap<Ty<'tcx>>, usize> {
+ -> Result<(), usize> {
let time_passes = tcx.sess.time_passes();
- let ccx = CrateCtxt {
- ast_ty_to_ty_cache: RefCell::new(NodeMap()),
- all_traits: RefCell::new(None),
- stack: RefCell::new(Vec::new()),
- tcx: tcx,
- deferred_obligations: RefCell::new(NodeMap()),
- };
// this ensures that later parts of type checking can assume that items
// have valid types and not error
tcx.sess.track_errors(|| {
time(time_passes, "type collecting", ||
- collect::collect_item_types(&ccx));
+ collect::collect_item_types(tcx));
})?;
tcx.sess.track_errors(|| {
time(time_passes, "impl wf inference", ||
- impl_wf_check::impl_wf_check(&ccx));
+ impl_wf_check::impl_wf_check(tcx));
})?;
tcx.sess.track_errors(|| {
time(time_passes, "coherence checking", ||
- coherence::check_coherence(&ccx));
+ coherence::check_coherence(tcx));
})?;
- time(time_passes, "wf checking", || check::check_wf_new(&ccx))?;
+ time(time_passes, "wf checking", || check::check_wf_new(tcx))?;
- time(time_passes, "item-types checking", || check::check_item_types(&ccx))?;
+ time(time_passes, "item-types checking", || check::check_item_types(tcx))?;
- time(time_passes, "item-bodies checking", || check::check_item_bodies(&ccx))?;
+ time(time_passes, "item-bodies checking", || check::check_item_bodies(tcx))?;
- time(time_passes, "drop-impl checking", || check::check_drop_impls(&ccx))?;
+ time(time_passes, "drop-impl checking", || check::check_drop_impls(tcx))?;
check_unused::check_crate(tcx);
- check_for_entry_fn(&ccx);
+ check_for_entry_fn(tcx);
let err_count = tcx.sess.err_count();
if err_count == 0 {
- Ok(ccx.ast_ty_to_ty_cache.into_inner())
+ Ok(())
} else {
Err(err_count)
}
//! The second pass over the AST determines the set of constraints.
//! We walk the set of items and, for each member, generate new constraints.
-use dep_graph::DepTrackingMapConfig;
use hir::def_id::DefId;
use middle::resolve_lifetime as rl;
use rustc::ty::subst::Substs;
use rustc::ty::{self, Ty, TyCtxt};
-use rustc::ty::maps::ItemVariances;
use rustc::hir::map as hir_map;
use syntax::ast;
use rustc::hir;
use super::terms::VarianceTerm::*;
use super::xform::*;
+use dep_graph::DepNode::ItemSignature as VarianceDepNode;
+
pub struct ConstraintContext<'a, 'tcx: 'a> {
pub terms_cx: TermsContext<'a, 'tcx>,
};
// See README.md for a discussion on dep-graph management.
- tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id),
- &mut constraint_cx);
+ tcx.visit_all_item_likes_in_krate(VarianceDepNode, &mut constraint_cx);
constraint_cx
}
}
fn add_constraints_from_trait_ref(&mut self,
- generics: &ty::Generics<'tcx>,
+ generics: &ty::Generics,
trait_ref: ty::TraitRef<'tcx>,
variance: VarianceTermPtr<'a>) {
debug!("add_constraints_from_trait_ref: trait_ref={:?} variance={:?}",
// This edge is actually implied by the call to
// `lookup_trait_def`, but I'm trying to be future-proof. See
// README.md for a discussion on dep-graph management.
- self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
+ self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id));
self.add_constraints_from_substs(generics,
trait_ref.def_id,
/// in a context with the generics defined in `generics` and
/// ambient variance `variance`
fn add_constraints_from_ty(&mut self,
- generics: &ty::Generics<'tcx>,
+ generics: &ty::Generics,
ty: Ty<'tcx>,
variance: VarianceTermPtr<'a>) {
debug!("add_constraints_from_ty(ty={:?}, variance={:?})",
// This edge is actually implied by the call to
// `lookup_trait_def`, but I'm trying to be future-proof. See
// README.md for a discussion on dep-graph management.
- self.tcx().dep_graph.read(ItemVariances::to_dep_node(&def.did));
+ self.tcx().dep_graph.read(VarianceDepNode(def.did));
self.add_constraints_from_substs(generics,
def.did,
// This edge is actually implied by the call to
// `lookup_trait_def`, but I'm trying to be future-proof. See
// README.md for a discussion on dep-graph management.
- self.tcx().dep_graph.read(ItemVariances::to_dep_node(&trait_ref.def_id));
+ self.tcx().dep_graph.read(VarianceDepNode(trait_ref.def_id));
self.add_constraints_from_substs(generics,
trait_ref.def_id,
}
}
- ty::TyFnDef(.., &ty::BareFnTy { ref sig, .. }) |
- ty::TyFnPtr(&ty::BareFnTy { ref sig, .. }) => {
+ ty::TyFnDef(.., sig) |
+ ty::TyFnPtr(sig) => {
self.add_constraints_from_sig(generics, sig, variance);
}
/// Adds constraints appropriate for a nominal type (enum, struct,
/// object, etc) appearing in a context with ambient variance `variance`
fn add_constraints_from_substs(&mut self,
- generics: &ty::Generics<'tcx>,
+ generics: &ty::Generics,
def_id: DefId,
- type_param_defs: &[ty::TypeParameterDef<'tcx>],
+ type_param_defs: &[ty::TypeParameterDef],
region_param_defs: &[ty::RegionParameterDef],
substs: &Substs<'tcx>,
variance: VarianceTermPtr<'a>) {
/// Adds constraints appropriate for a function with signature
/// `sig` appearing in a context with ambient variance `variance`
fn add_constraints_from_sig(&mut self,
- generics: &ty::Generics<'tcx>,
- sig: &ty::PolyFnSig<'tcx>,
+ generics: &ty::Generics,
+ sig: ty::PolyFnSig<'tcx>,
variance: VarianceTermPtr<'a>) {
let contra = self.contravariant(variance);
for &input in sig.0.inputs() {
/// Adds constraints appropriate for a region appearing in a
/// context with ambient variance `variance`
fn add_constraints_from_region(&mut self,
- generics: &ty::Generics<'tcx>,
+ generics: &ty::Generics,
region: &'tcx ty::Region,
variance: VarianceTermPtr<'a>) {
match *region {
/// Adds constraints appropriate for a mutability-type pair
/// appearing in a context with ambient variance `variance`
fn add_constraints_from_mt(&mut self,
- generics: &ty::Generics<'tcx>,
+ generics: &ty::Generics,
mt: &ty::TypeAndMut<'tcx>,
variance: VarianceTermPtr<'a>) {
match mt.mutbl {
item_variances);
}
- tcx.item_variance_map
+ tcx.maps.variances
.borrow_mut()
.insert(item_def_id, Rc::new(item_variances));
}
// a variable.
use arena::TypedArena;
-use dep_graph::DepTrackingMapConfig;
use rustc::ty::{self, TyCtxt};
-use rustc::ty::maps::ItemVariances;
use std::fmt;
use std::rc::Rc;
use syntax::ast;
pub type VarianceTermPtr<'a> = &'a VarianceTerm<'a>;
+use dep_graph::DepNode::ItemSignature as VarianceDepNode;
+
#[derive(Copy, Clone, Debug)]
pub struct InferredIndex(pub usize);
};
// See README.md for a discussion on dep-graph management.
- tcx.visit_all_item_likes_in_krate(|def_id| ItemVariances::to_dep_node(&def_id), &mut terms_cx);
+ tcx.visit_all_item_likes_in_krate(|def_id| VarianceDepNode(def_id), &mut terms_cx);
terms_cx
}
// parameters".
if self.num_inferred() == inferreds_on_entry {
let item_def_id = self.tcx.hir.local_def_id(item_id);
- self.tcx
- .item_variance_map
+ self.tcx.maps.variances
.borrow_mut()
.insert(item_def_id, self.empty_variances.clone());
}
use std::iter::once;
use syntax::ast;
+use syntax_pos::DUMMY_SP;
use rustc::hir;
use rustc::hir::def::{Def, CtorKind};
}
fn build_external_function(cx: &DocContext, did: DefId) -> clean::Function {
- let ty = cx.tcx.item_type(did);
- let (decl, style, abi) = match ty.sty {
- ty::TyFnDef(.., ref f) => ((did, &f.sig).clean(cx), f.unsafety, f.abi),
- _ => panic!("bad function"),
- };
+ let sig = cx.tcx.item_type(did).fn_sig();
let constness = if cx.tcx.sess.cstore.is_const_fn(did) {
hir::Constness::Const
let predicates = cx.tcx.item_predicates(did);
clean::Function {
- decl: decl,
+ decl: (did, sig).clean(cx),
generics: (cx.tcx.item_generics(did), &predicates).clean(cx),
- unsafety: style,
+ unsafety: sig.unsafety(),
constness: constness,
- abi: abi,
+ abi: sig.abi(),
}
}
pub fn build_impls(cx: &DocContext, did: DefId) -> Vec<clean::Item> {
let tcx = cx.tcx;
- tcx.populate_inherent_implementations_for_type_if_necessary(did);
+ tcx.populate_inherent_implementations_for_type_if_necessary(DUMMY_SP, did);
let mut impls = Vec::new();
- if let Some(i) = tcx.inherent_impls.borrow().get(&did) {
+ if let Some(i) = tcx.maps.inherent_impls.borrow().get(&did) {
for &did in i.iter() {
build_impl(cx, did, &mut impls);
}
}
}
-impl<'tcx> Clean<TyParam> for ty::TypeParameterDef<'tcx> {
+impl<'tcx> Clean<TyParam> for ty::TypeParameterDef {
fn clean(&self, cx: &DocContext) -> TyParam {
cx.renderinfo.borrow_mut().external_typarams.insert(self.def_id, self.name.clean(cx));
TyParam {
name: self.name.clean(cx),
did: self.def_id,
bounds: vec![], // these are filled in from the where-clauses
- default: self.default.clean(cx),
+ default: if self.has_default {
+ Some(cx.tcx.item_type(self.def_id).clean(cx))
+ } else {
+ None
+ }
}
}
}
}
}
-impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics<'tcx>,
+impl<'a, 'tcx> Clean<Generics> for (&'a ty::Generics,
&'a ty::GenericPredicates<'tcx>) {
fn clean(&self, cx: &DocContext) -> Generics {
use self::WherePredicate as WP;
}
}
-impl<'a, 'tcx> Clean<FnDecl> for (DefId, &'a ty::PolyFnSig<'tcx>) {
+impl<'a, 'tcx> Clean<FnDecl> for (DefId, ty::PolyFnSig<'tcx>) {
fn clean(&self, cx: &DocContext) -> FnDecl {
let (did, sig) = *self;
let mut names = if cx.tcx.hir.as_local_node_id(did).is_some() {
ty::AssociatedKind::Method => {
let generics = (cx.tcx.item_generics(self.def_id),
&cx.tcx.item_predicates(self.def_id)).clean(cx);
- let fty = match cx.tcx.item_type(self.def_id).sty {
- ty::TyFnDef(_, _, f) => f,
- _ => unreachable!()
- };
- let mut decl = (self.def_id, &fty.sig).clean(cx);
+ let sig = cx.tcx.item_type(self.def_id).fn_sig();
+ let mut decl = (self.def_id, sig).clean(cx);
if self.method_has_self_argument {
let self_ty = match self.container {
}
ty::TraitContainer(_) => cx.tcx.mk_self_type()
};
- let self_arg_ty = *fty.sig.input(0).skip_binder();
+ let self_arg_ty = *sig.input(0).skip_binder();
if self_arg_ty == self_ty {
decl.inputs.values[0].type_ = Generic(String::from("Self"));
} else if let ty::TyRef(_, mt) = self_arg_ty.sty {
};
if provided {
MethodItem(Method {
- unsafety: fty.unsafety,
+ unsafety: sig.unsafety(),
generics: generics,
decl: decl,
- abi: fty.abi,
+ abi: sig.abi(),
// trait methods canot (currently, at least) be const
constness: hir::Constness::NotConst,
})
} else {
TyMethodItem(TyMethod {
- unsafety: fty.unsafety,
+ unsafety: sig.unsafety(),
generics: generics,
decl: decl,
- abi: fty.abi,
+ abi: sig.abi(),
})
}
}
}
TyPath(hir::QPath::TypeRelative(ref qself, ref segment)) => {
let mut def = Def::Err;
- if let Some(ty) = cx.hir_ty_to_ty.get(&self.id) {
+ if let Some(ty) = cx.tcx.ast_ty_to_ty_cache.borrow().get(&self.id) {
if let ty::TyProjection(proj) = ty.sty {
def = Def::Trait(proj.trait_ref.def_id);
}
mutability: mt.mutbl.clean(cx),
type_: box mt.ty.clean(cx),
},
- ty::TyFnDef(.., ref fty) |
- ty::TyFnPtr(ref fty) => BareFunction(box BareFunctionDecl {
- unsafety: fty.unsafety,
+ ty::TyFnDef(.., sig) |
+ ty::TyFnPtr(sig) => BareFunction(box BareFunctionDecl {
+ unsafety: sig.unsafety(),
generics: Generics {
lifetimes: Vec::new(),
type_params: Vec::new(),
where_predicates: Vec::new()
},
- decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), &fty.sig).clean(cx),
- abi: fty.abi,
+ decl: (cx.tcx.hir.local_def_id(ast::CRATE_NODE_ID), sig).clean(cx),
+ abi: sig.abi(),
}),
ty::TyAdt(def, substs) => {
let did = def.did;
use rustc::hir::def_id::DefId;
use rustc::hir::def::{Def, ExportMap};
use rustc::middle::privacy::AccessLevels;
-use rustc::ty::{self, TyCtxt, GlobalArenas, Ty};
+use rustc::ty::{self, TyCtxt, GlobalArenas};
use rustc::hir::map as hir_map;
use rustc::lint;
-use rustc::util::nodemap::{FxHashMap, NodeMap};
+use rustc::util::nodemap::FxHashMap;
use rustc_trans::back::link;
use rustc_resolve as resolve;
use rustc_metadata::cstore::CStore;
/// Table node id of lifetime parameter definition -> substituted lifetime
pub lt_substs: RefCell<FxHashMap<ast::NodeId, clean::Lifetime>>,
pub export_map: ExportMap,
-
- /// Table from HIR Ty nodes to their resolved Ty.
- pub hir_ty_to_ty: NodeMap<Ty<'tcx>>,
}
impl<'a, 'tcx> DocContext<'a, 'tcx> {
sess.fatal("Compilation failed, aborting rustdoc");
}
- let ty::CrateAnalysis { access_levels, export_map, hir_ty_to_ty, .. } = analysis;
+ let ty::CrateAnalysis { access_levels, export_map, .. } = analysis;
// Convert from a NodeId set to a DefId set since we don't always have easy access
// to the map from defid -> nodeid
ty_substs: Default::default(),
lt_substs: Default::default(),
export_map: export_map,
- hir_ty_to_ty: hir_ty_to_ty,
};
debug!("crate: {:?}", tcx.hir.krate());
&cx.shared.issue_tracker_base_url,
stab.issue) {
(true, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
- format!(" (<code>{}</code> <a href=\"{}{}\">#{}</a>)",
+ format!(" (<code>{} </code><a href=\"{}{}\">#{}</a>)",
Escape(&stab.feature), tracker_url, issue_no, issue_no),
(false, &Some(ref tracker_url), Some(issue_no)) if issue_no > 0 =>
format!(" (<a href=\"{}{}\">#{}</a>)", Escape(&tracker_url), issue_no,
if stab.unstable_reason.is_empty() {
stability.push(format!("<div class='stab unstable'>\
<span class=microscope>🔬</span> \
- This is a nightly-only experimental API. {}\
+ This is a nightly-only experimental API. {}\
</div>",
- unstable_extra));
+ unstable_extra));
} else {
let text = format!("<summary><span class=microscope>🔬</span> \
- This is a nightly-only experimental API. {}\
+ This is a nightly-only experimental API. {}\
</summary>{}",
unstable_extra, MarkdownHtml(&stab.unstable_reason));
stability.push(format!("<div class='stab unstable'><details>{}</details></div>",
use std::ffi::OsString;
use std::io::prelude::*;
use std::io;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
use std::panic::{self, AssertUnwindSafe};
use std::process::Command;
use std::rc::Rc;
pub fn get_filename(&self) -> String {
if let Some(ref codemap) = self.codemap {
- codemap.span_to_filename(self.position)
+ let filename = codemap.span_to_filename(self.position);
+ if let Ok(cur_dir) = env::current_dir() {
+ if let Ok(path) = Path::new(&filename).strip_prefix(&cur_dir) {
+ if let Some(path) = path.to_str() {
+ return path.to_owned();
+ }
+ }
+ }
+ filename
} else if let Some(ref filename) = self.filename {
filename.clone()
} else {
self.inside_public_path = orig_inside_public_path;
if let Some(exports) = self.cx.export_map.get(&id) {
for export in exports {
- if let Def::Macro(def_id) = export.def {
+ if let Def::Macro(def_id, ..) = export.def {
if def_id.krate == LOCAL_CRATE {
continue // These are `krate.exported_macros`, handled in `self.visit()`.
}
/// specific rustdoc annotations into account (i.e. `doc(hidden)`)
pub struct LibEmbargoVisitor<'a, 'b: 'a, 'tcx: 'b> {
cx: &'a ::core::DocContext<'b, 'tcx>,
- cstore: &'a CrateStore<'tcx>,
+ cstore: &'a CrateStore,
// Accessibility levels for reachable nodes
access_levels: RefMut<'a, AccessLevels<DefId>>,
// Previous accessibility level, None means unreachable
println!("cargo:rustc-link-lib=userenv");
println!("cargo:rustc-link-lib=shell32");
} else if target.contains("fuchsia") {
+ // use system-provided libbacktrace
+ if cfg!(feature = "backtrace") {
+ println!("cargo:rustc-link-lib=backtrace");
+ }
println!("cargo:rustc-link-lib=magenta");
println!("cargo:rustc-link-lib=mxio");
println!("cargo:rustc-link-lib=launchpad"); // for std::process
// ----------------------
// To protect against degenerate performance scenarios (including DOS attacks),
// the implementation includes an adaptive behavior that can resize the map
-// early (before its capacity is exceeded) when suspiciously long probe or
-// forward shifts sequences are encountered.
+// early (before its capacity is exceeded) when suspiciously long probe sequences
+// are encountered.
//
// With this algorithm in place it would be possible to turn a CPU attack into
// a memory attack due to the aggressive resizing. To prevent that the
-// adaptive behavior only triggers when the map occupancy is half the maximum occupancy.
+// adaptive behavior only triggers when the map is at least half full.
// This reduces the effectiveness of the algorithm but also makes it completely safe.
//
// The previous safety measure also prevents degenerate interactions with
// DOS attack.
//
const DISPLACEMENT_THRESHOLD: usize = 128;
-const FORWARD_SHIFT_THRESHOLD: usize = 512;
//
-// The thresholds of 128 and 512 are chosen to minimize the chance of exceeding them.
+// The threshold of 128 is chosen to minimize the chance of exceeding it.
// In particular, we want that chance to be less than 10^-8 with a load of 90%.
// For displacement, the smallest constant that fits our needs is 90,
-// so we round that up to 128. For the number of forward-shifted buckets,
-// we choose k=512. Keep in mind that the run length is a sum of the displacement and
-// the number of forward-shifted buckets, so its threshold is 128+512=640.
-// Even though the probability of having a run length of more than 640 buckets may be
-// higher than the probability we want, it should be low enough.
+// so we round that up to 128.
//
// At a load factor of α, the odds of finding the target bucket after exactly n
// unsuccesful probes[1] are
// Pr_α{displacement = n} =
// (1 - α) / α * ∑_{k≥1} e^(-kα) * (kα)^(k+n) / (k + n)! * (1 - kα / (k + n + 1))
//
-// We use this formula to find the probability of loading half of triggering the adaptive behavior
+// We use this formula to find the probability of triggering the adaptive behavior
//
// Pr_0.909{displacement > 128} = 1.601 * 10^-11
//
-// FIXME: Extend with math for shift threshold in [2]
-//
// 1. Alfredo Viola (2005). Distributional analysis of Robin Hood linear probing
// hashing with buckets.
-// 2. http://www.cs.tau.ac.il/~zwick/Adv-Alg-2015/Linear-Probing.pdf
-
/// A hash map implementation which uses linear probing with Robin Hood bucket
/// stealing.
mut hash: SafeHash,
mut key: K,
mut val: V)
- -> (usize, &'a mut V) {
+ -> &'a mut V {
let start_index = bucket.index();
let size = bucket.table().size();
// Save the *starting point*.
Empty(bucket) => {
// Found a hole!
let bucket = bucket.put(hash, key, val);
- let end_index = bucket.index();
// Now that it's stolen, just read the value's pointer
// right out of the table! Go back to the *starting point*.
//
// bucket, which is a FullBucket on top of a
// FullBucketMut, into just one FullBucketMut. The "table"
// refers to the inner FullBucketMut in this context.
- return (end_index - start_index, bucket.into_table().into_mut_refs().1);
+ return bucket.into_table().into_mut_refs().1;
}
Full(bucket) => bucket,
};
pub fn insert(self, value: V) -> &'a mut V {
match self.elem {
NeqElem(bucket, disp) => {
- let (shift, v_ref) = robin_hood(bucket, disp, self.hash, self.key, value);
- if disp >= DISPLACEMENT_THRESHOLD || shift >= FORWARD_SHIFT_THRESHOLD {
+ if disp >= DISPLACEMENT_THRESHOLD {
*self.long_probes = true;
}
- v_ref
+ robin_hood(bucket, disp, self.hash, self.key, value)
},
NoElem(bucket, disp) => {
if disp >= DISPLACEMENT_THRESHOLD {
*self.long_probes = true;
}
- let bucket = bucket.put(self.hash, self.key, value);
- bucket.into_mut_refs().1
+ bucket.put(self.hash, self.key, value).into_mut_refs().1
},
}
}
#[stable(feature = "catch_unwind", since = "1.9.0")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for *mut T {}
#[unstable(feature = "unique", issue = "27730")]
-impl<T: UnwindSafe> UnwindSafe for Unique<T> {}
+impl<T: UnwindSafe + ?Sized> UnwindSafe for Unique<T> {}
#[unstable(feature = "shared", issue = "27730")]
impl<T: RefUnwindSafe + ?Sized> UnwindSafe for Shared<T> {}
#[stable(feature = "catch_unwind", since = "1.9.0")]
let log_backtrace = {
let panics = update_panic_count(0);
- panics >= 2 || backtrace::log_enabled()
+ if panics >= 2 {
+ Some(backtrace::PrintFormat::Full)
+ } else {
+ backtrace::log_enabled()
+ }
};
let file = info.location.file;
static FIRST_PANIC: AtomicBool = AtomicBool::new(true);
- if log_backtrace {
- let _ = backtrace::write(err);
+ if let Some(format) = log_backtrace {
+ let _ = backtrace::print(err, format);
} else if FIRST_PANIC.compare_and_swap(true, false, Ordering::SeqCst) {
let _ = writeln!(err, "note: Run with `RUST_BACKTRACE=1` for a backtrace.");
}
//!
//! assert!(ecode.success());
//! ```
+//!
+//! Calling a command with input and reading its output:
+//!
+//! ```no_run
+//! use std::process::{Command, Stdio};
+//! use std::io::Write;
+//!
+//! let mut child = Command::new("/bin/cat")
+//! .stdin(Stdio::piped())
+//! .stdout(Stdio::piped())
+//! .spawn()
+//! .expect("failed to execute child");
+//!
+//! {
+//! // limited borrow of stdin
+//! let stdin = child.stdin.as_mut().expect("failed to get stdin");
+//! stdin.write_all(b"test").expect("failed to write to stdin");
+//! }
+//!
+//! let output = child
+//! .wait_with_output()
+//! .expect("failed to wait on child");
+//!
+//! assert_eq!(b"test", output.stdout.as_slice());
+//! ```
#![stable(feature = "process", since = "1.0.0")]
/// A barrier enables multiple threads to synchronize the beginning
/// of some computation.
///
+/// # Examples
+///
/// ```
/// use std::sync::{Arc, Barrier};
/// use std::thread;
/// A result returned from wait.
///
-/// Currently this opaque structure only has one method, `.is_leader()`. Only
+/// Currently this opaque structure only has one method, [`.is_leader()`]. Only
/// one thread will receive a result that will return `true` from this function.
+///
+/// [`.is_leader()`]: #method.is_leader
+///
+/// # Examples
+///
+/// ```
+/// use std::sync::Barrier;
+///
+/// let barrier = Barrier::new(1);
+/// let barrier_wait_result = barrier.wait();
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub struct BarrierWaitResult(bool);
impl Barrier {
/// Creates a new barrier that can block a given number of threads.
///
- /// A barrier will block `n`-1 threads which call `wait` and then wake up
- /// all threads at once when the `n`th thread calls `wait`.
+ /// A barrier will block `n`-1 threads which call [`wait`] and then wake up
+ /// all threads at once when the `n`th thread calls [`wait`].
+ ///
+ /// [`wait`]: #method.wait
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Barrier;
+ ///
+ /// let barrier = Barrier::new(10);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new(n: usize) -> Barrier {
Barrier {
/// Barriers are re-usable after all threads have rendezvoused once, and can
/// be used continuously.
///
- /// A single (arbitrary) thread will receive a `BarrierWaitResult` that
- /// returns `true` from `is_leader` when returning from this function, and
+ /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that
+ /// returns `true` from [`is_leader`] when returning from this function, and
/// all other threads will receive a result that will return `false` from
- /// `is_leader`
+ /// [`is_leader`].
+ ///
+ /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html
+ /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Barrier};
+ /// use std::thread;
+ ///
+ /// let mut handles = Vec::with_capacity(10);
+ /// let barrier = Arc::new(Barrier::new(10));
+ /// for _ in 0..10 {
+ /// let c = barrier.clone();
+ /// // The same messages will be printed together.
+ /// // You will NOT see any interleaving.
+ /// handles.push(thread::spawn(move|| {
+ /// println!("before wait");
+ /// c.wait();
+ /// println!("after wait");
+ /// }));
+ /// }
+ /// // Wait for other threads to finish.
+ /// for handle in handles {
+ /// handle.join().unwrap();
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn wait(&self) -> BarrierWaitResult {
let mut lock = self.lock.lock().unwrap();
}
impl BarrierWaitResult {
- /// Returns whether this thread from `wait` is the "leader thread".
+ /// Returns whether this thread from [`wait`] is the "leader thread".
///
/// Only one thread will have `true` returned from their result, all other
/// threads will have `false` returned.
+ ///
+ /// [`wait`]: struct.Barrier.html#method.wait
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Barrier;
+ ///
+ /// let barrier = Barrier::new(1);
+ /// let barrier_wait_result = barrier.wait();
+ /// println!("{:?}", barrier_wait_result.is_leader());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn is_leader(&self) -> bool { self.0 }
}
/// A type indicating whether a timed wait on a condition variable returned
/// due to a time out or not.
+///
+/// It is returned by the [`wait_timeout`] method.
+///
+/// [`wait_timeout`]: struct.Condvar.html#method.wait_timeout
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
#[stable(feature = "wait_timeout", since = "1.5.0")]
pub struct WaitTimeoutResult(bool);
impl WaitTimeoutResult {
/// Returns whether the wait was known to have timed out.
+ ///
+ /// # Examples
+ ///
+ /// This example spawns a thread which will update the boolean value and
+ /// then wait 100 milliseconds before notifying the condvar.
+ ///
+ /// The main thread will wait with a timeout on the condvar and then leave
+ /// once the boolean has been updated and notified.
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// // We update the boolean value.
+ /// *started = true;
+ /// // Let's wait 20 milliseconds before notifying the condvar.
+ /// thread::sleep(Duration::from_millis(20));
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// loop {
+ /// // Let's put a timeout on the condvar's wait.
+ /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
+ /// // 10 milliseconds have passed, or maybe the value changed!
+ /// started = result.0;
+ /// if *started == true {
+ /// // We received the notification and the value has been updated, we can leave.
+ /// break
+ /// }
+ /// }
+ /// ```
#[stable(feature = "wait_timeout", since = "1.5.0")]
pub fn timed_out(&self) -> bool {
self.0
/// let pair = Arc::new((Mutex::new(false), Condvar::new()));
/// let pair2 = pair.clone();
///
-/// // Inside of our lock, spawn a new thread, and then wait for it to start
+/// // Inside of our lock, spawn a new thread, and then wait for it to start.
/// thread::spawn(move|| {
/// let &(ref lock, ref cvar) = &*pair2;
/// let mut started = lock.lock().unwrap();
/// *started = true;
+/// // We notify the condvar that the value has changed.
/// cvar.notify_one();
/// });
///
-/// // wait for the thread to start up
+/// // Wait for the thread to start up.
/// let &(ref lock, ref cvar) = &*pair;
/// let mut started = lock.lock().unwrap();
/// while !*started {
impl Condvar {
/// Creates a new condition variable which is ready to be waited on and
/// notified.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::Condvar;
+ ///
+ /// let condvar = Condvar::new();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> Condvar {
let mut c = Condvar {
/// notification.
///
/// This function will atomically unlock the mutex specified (represented by
- /// `mutex_guard`) and block the current thread. This means that any calls
- /// to `notify_*()` which happen logically after the mutex is unlocked are
- /// candidates to wake this thread up. When this function call returns, the
- /// lock specified will have been re-acquired.
+ /// `guard`) and block the current thread. This means that any calls
+ /// to [`notify_one()`] or [`notify_all()`] which happen logically after the
+ /// mutex is unlocked are candidates to wake this thread up. When this
+ /// function call returns, the lock specified will have been re-acquired.
///
/// Note that this function is susceptible to spurious wakeups. Condition
/// variables normally have a boolean predicate associated with them, and
///
/// This function will return an error if the mutex being waited on is
/// poisoned when this thread re-acquires the lock. For more information,
- /// see information about poisoning on the Mutex type.
+ /// see information about [poisoning] on the [`Mutex`] type.
///
/// # Panics
///
- /// This function will `panic!()` if it is used with more than one mutex
+ /// This function will [`panic!()`] if it is used with more than one mutex
/// over time. Each condition variable is dynamically bound to exactly one
/// mutex to ensure defined behavior across platforms. If this functionality
/// is not desired, then unsafe primitives in `sys` are provided.
+ ///
+ /// [`notify_one()`]: #method.notify_one
+ /// [`notify_all()`]: #method.notify_all
+ /// [poisoning]: ../sync/struct.Mutex.html#poisoning
+ /// [`Mutex`]: ../sync/struct.Mutex.html
+ /// [`panic!()`]: ../../std/macro.panic.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // As long as the value inside the `Mutex` is false, we wait.
+ /// while !*started {
+ /// started = cvar.wait(started).unwrap();
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn wait<'a, T>(&self, guard: MutexGuard<'a, T>)
-> LockResult<MutexGuard<'a, T>> {
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
- /// The semantics of this function are equivalent to `wait()`
+ /// The semantics of this function are equivalent to [`wait`]
/// except that the thread will be blocked for roughly no longer
/// than `ms` milliseconds. This method should not be used for
/// precise timing due to anomalies such as preemption or platform
/// The returned boolean is `false` only if the timeout is known
/// to have elapsed.
///
- /// Like `wait`, the lock specified will be re-acquired when this function
+ /// Like [`wait`], the lock specified will be re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
+ ///
+ /// [`wait`]: #method.wait
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // As long as the value inside the `Mutex` is false, we wait.
+ /// loop {
+ /// let result = cvar.wait_timeout_ms(started, 10).unwrap();
+ /// // 10 milliseconds have passed, or maybe the value changed!
+ /// started = result.0;
+ /// if *started == true {
+ /// // We received the notification and the value has been updated, we can leave.
+ /// break
+ /// }
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::sync::Condvar::wait_timeout`")]
pub fn wait_timeout_ms<'a, T>(&self, guard: MutexGuard<'a, T>, ms: u32)
/// Waits on this condition variable for a notification, timing out after a
/// specified duration.
///
- /// The semantics of this function are equivalent to `wait()` except that
+ /// The semantics of this function are equivalent to [`wait`] except that
/// the thread will be blocked for roughly no longer than `dur`. This
/// method should not be used for precise timing due to anomalies such as
/// preemption or platform differences that may not cause the maximum
/// measured with a monotonic clock, and not affected by the changes made to
/// the system time.
///
- /// The returned `WaitTimeoutResult` value indicates if the timeout is
+ /// The returned [`WaitTimeoutResult`] value indicates if the timeout is
/// known to have elapsed.
///
- /// Like `wait`, the lock specified will be re-acquired when this function
+ /// Like [`wait`], the lock specified will be re-acquired when this function
/// returns, regardless of whether the timeout elapsed or not.
+ ///
+ /// [`wait`]: #method.wait
+ /// [`WaitTimeoutResult`]: struct.WaitTimeoutResult.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ /// use std::time::Duration;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // wait for the thread to start up
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // as long as the value inside the `Mutex` is false, we wait
+ /// loop {
+ /// let result = cvar.wait_timeout(started, Duration::from_millis(10)).unwrap();
+ /// // 10 milliseconds have passed, or maybe the value changed!
+ /// started = result.0;
+ /// if *started == true {
+ /// // We received the notification and the value has been updated, we can leave.
+ /// break
+ /// }
+ /// }
+ /// ```
#[stable(feature = "wait_timeout", since = "1.5.0")]
pub fn wait_timeout<'a, T>(&self, guard: MutexGuard<'a, T>,
dur: Duration)
/// Wakes up one blocked thread on this condvar.
///
/// If there is a blocked thread on this condition variable, then it will
- /// be woken up from its call to `wait` or `wait_timeout`. Calls to
+ /// be woken up from its call to [`wait`] or [`wait_timeout`]. Calls to
/// `notify_one` are not buffered in any way.
///
- /// To wake up all threads, see `notify_all()`.
+ /// To wake up all threads, see [`notify_all()`].
+ ///
+ /// [`wait`]: #method.wait
+ /// [`wait_timeout`]: #method.wait_timeout
+ /// [`notify_all()`]: #method.notify_all
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_one();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // As long as the value inside the `Mutex` is false, we wait.
+ /// while !*started {
+ /// started = cvar.wait(started).unwrap();
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn notify_one(&self) {
unsafe { self.inner.notify_one() }
/// variable are awoken. Calls to `notify_all()` are not buffered in any
/// way.
///
- /// To wake up only one thread, see `notify_one()`.
+ /// To wake up only one thread, see [`notify_one()`].
+ ///
+ /// [`notify_one()`]: #method.notify_one
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::sync::{Arc, Mutex, Condvar};
+ /// use std::thread;
+ ///
+ /// let pair = Arc::new((Mutex::new(false), Condvar::new()));
+ /// let pair2 = pair.clone();
+ ///
+ /// thread::spawn(move|| {
+ /// let &(ref lock, ref cvar) = &*pair2;
+ /// let mut started = lock.lock().unwrap();
+ /// *started = true;
+ /// // We notify the condvar that the value has changed.
+ /// cvar.notify_all();
+ /// });
+ ///
+ /// // Wait for the thread to start up.
+ /// let &(ref lock, ref cvar) = &*pair;
+ /// let mut started = lock.lock().unwrap();
+ /// // As long as the value inside the `Mutex` is false, we wait.
+ /// while !*started {
+ /// started = cvar.wait(started).unwrap();
+ /// }
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn notify_all(&self) {
unsafe { self.inner.notify_all() }
/// dropped (falls out of scope), the lock will be unlocked.
///
/// The data protected by the mutex can be access through this guard via its
-/// `Deref` and `DerefMut` implementations.
+/// [`Deref`] and [`DerefMut`] implementations.
///
/// This structure is created by the [`lock()`] and [`try_lock()`] methods on
/// [`Mutex`].
///
+/// [`Deref`]: ../../std/ops/trait.Deref.html
+/// [`DerefMut`]: ../../std/ops/trait.DerefMut.html
/// [`lock()`]: struct.Mutex.html#method.lock
/// [`try_lock()`]: struct.Mutex.html#method.try_lock
/// [`Mutex`]: struct.Mutex.html
use libc;
use io;
-use sys_common::backtrace::output;
+use sys_common::backtrace::Frame;
+
+pub use sys_common::gnu::libbacktrace::*;
+pub struct BacktraceContext;
#[inline(never)]
-pub fn write(w: &mut io::Write) -> io::Result<()> {
- output(w, 0, 0 as *mut libc::c_void, None)
+pub fn unwind_backtrace(frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ Ok((0, BacktraceContext))
}
use io::{self, ErrorKind};
pub mod args;
-#[cfg(any(not(cargobuild), feature = "backtrace"))]
+#[cfg(feature = "backtrace")]
pub mod backtrace;
pub mod condvar;
pub mod env;
Ok(path_to_local_addr(path.to_str().unwrap_or("")))
}
+ pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented"))
+ }
+
pub fn shutdown(&self, _how: Shutdown) -> Result<()> {
Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented"))
}
Ok(path_to_local_addr(path.to_str().unwrap_or("")))
}
+ pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::peek not implemented"))
+ }
+
+ pub fn peek_from(&self, _buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::peek_from not implemented"))
+ }
+
pub fn broadcast(&self) -> Result<bool> {
Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented"))
}
/// to symbols. This is a bit of a hokey implementation as-is, but it works for
/// all unix platforms we support right now, so it at least gets the job done.
-pub use self::tracing::write;
+pub use self::tracing::unwind_backtrace;
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
// tracing impls:
mod tracing;
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
}
}
+
+pub struct BacktraceContext;
// except according to those terms.
use io;
-use io::prelude::*;
+use intrinsics;
+use ffi::CStr;
use libc;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
-pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
- _symaddr: *mut libc::c_void) -> io::Result<()> {
- use sys_common::backtrace::{output};
- use intrinsics;
- use ffi::CStr;
-
- #[repr(C)]
- struct Dl_info {
- dli_fname: *const libc::c_char,
- dli_fbase: *mut libc::c_void,
- dli_sname: *const libc::c_char,
- dli_saddr: *mut libc::c_void,
- }
- extern {
- fn dladdr(addr: *const libc::c_void,
- info: *mut Dl_info) -> libc::c_int;
+pub fn resolve_symname<F>(frame: Frame,
+ callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ unsafe {
+ let mut info: Dl_info = intrinsics::init();
+ let symname = if dladdr(frame.exact_position, &mut info) == 0 {
+ None
+ } else {
+ CStr::from_ptr(info.dli_sname).to_str().ok()
+ };
+ callback(symname)
}
+}
- let mut info: Dl_info = unsafe { intrinsics::init() };
- if unsafe { dladdr(addr, &mut info) == 0 } {
- output(w, idx,addr, None)
- } else {
- output(w, idx, addr, Some(unsafe {
- CStr::from_ptr(info.dli_sname).to_bytes()
- }))
- }
+pub fn foreach_symbol_fileline<F>(_symbol_addr: Frame,
+ _f: F,
+ _: &BacktraceContext) -> io::Result<bool>
+ where F: FnMut(&[u8], libc::c_int) -> io::Result<()>
+{
+ Ok(false)
+}
+
+#[repr(C)]
+struct Dl_info {
+ dli_fname: *const libc::c_char,
+ dli_fbase: *mut libc::c_void,
+ dli_sname: *const libc::c_char,
+ dli_saddr: *mut libc::c_void,
+}
+
+extern {
+ fn dladdr(addr: *const libc::c_void,
+ info: *mut Dl_info) -> libc::c_int;
}
+++ /dev/null
-// Copyright 2014 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.
-
-pub use sys_common::gnu::libbacktrace::print;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub use self::imp::print;
+pub use self::imp::{foreach_symbol_fileline, resolve_symname};
#[cfg(any(target_os = "macos", target_os = "ios",
target_os = "emscripten"))]
#[cfg(not(any(target_os = "macos", target_os = "ios",
target_os = "emscripten")))]
-#[path = "gnu.rs"]
-mod imp;
+mod imp {
+ pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+}
/// simple to use it should be used only on iOS devices as the only viable
/// option.
-use io::prelude::*;
use io;
use libc;
-use mem;
-use sys::mutex::Mutex;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
-use super::super::printing::print;
-
-#[inline(never)]
-pub fn write(w: &mut Write) -> io::Result<()> {
- extern {
- fn backtrace(buf: *mut *mut libc::c_void,
- sz: libc::c_int) -> libc::c_int;
+#[inline(never)] // if we know this is a function call, we can skip it when
+ // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ const FRAME_LEN: usize = 100;
+ assert!(FRAME_LEN >= frames.len());
+ let mut raw_frames = [::ptr::null_mut(); FRAME_LEN];
+ let nb_frames = unsafe {
+ backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int)
+ } as usize;
+ for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) {
+ *to = Frame {
+ exact_position: *from,
+ symbol_addr: *from,
+ };
}
+ Ok((nb_frames as usize, BacktraceContext))
+}
- // while it doesn't requires lock for work as everything is
- // local, it still displays much nicer backtraces when a
- // couple of threads panic simultaneously
- static LOCK: Mutex = Mutex::new();
- unsafe {
- LOCK.lock();
-
- writeln!(w, "stack backtrace:")?;
- // 100 lines should be enough
- const SIZE: usize = 100;
- let mut buf: [*mut libc::c_void; SIZE] = mem::zeroed();
- let cnt = backtrace(buf.as_mut_ptr(), SIZE as libc::c_int) as usize;
-
- // skipping the first one as it is write itself
- for i in 1..cnt {
- print(w, i as isize, buf[i], buf[i])?
- }
- LOCK.unlock();
- }
- Ok(())
+extern {
+ fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int;
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use error::Error;
use io;
-use io::prelude::*;
use libc;
-use mem;
-use sys_common::mutex::Mutex;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
-use super::super::printing::print;
use unwind as uw;
-#[inline(never)] // if we know this is a function call, we can skip it when
- // tracing
-pub fn write(w: &mut Write) -> io::Result<()> {
- struct Context<'a> {
- idx: isize,
- writer: &'a mut (Write+'a),
- last_error: Option<io::Error>,
- }
+struct Context<'a> {
+ idx: usize,
+ frames: &'a mut [Frame],
+}
- // When using libbacktrace, we use some necessary global state, so we
- // need to prevent more than one thread from entering this block. This
- // is semi-reasonable in terms of printing anyway, and we know that all
- // I/O done here is blocking I/O, not green I/O, so we don't have to
- // worry about this being a native vs green mutex.
- static LOCK: Mutex = Mutex::new();
- unsafe {
- LOCK.lock();
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
- writeln!(w, "stack backtrace:")?;
+impl Error for UnwindError {
+ fn description(&self) -> &'static str {
+ "unexpected return value while unwinding"
+ }
+}
- let mut cx = Context { writer: w, last_error: None, idx: 0 };
- let ret = match {
- uw::_Unwind_Backtrace(trace_fn,
- &mut cx as *mut Context as *mut libc::c_void)
- } {
- uw::_URC_NO_REASON => {
- match cx.last_error {
- Some(err) => Err(err),
- None => Ok(())
- }
- }
- _ => Ok(()),
- };
- LOCK.unlock();
- return ret
+impl ::fmt::Display for UnwindError {
+ fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+ write!(f, "{}: {:?}", self.description(), self.0)
}
+}
- extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
- arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
- let cx: &mut Context = unsafe { mem::transmute(arg) };
- let mut ip_before_insn = 0;
- let mut ip = unsafe {
- uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
- };
- if !ip.is_null() && ip_before_insn == 0 {
- // this is a non-signaling frame, so `ip` refers to the address
- // after the calling instruction. account for that.
- ip = (ip as usize - 1) as *mut _;
+#[inline(never)] // if we know this is a function call, we can skip it when
+ // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ let mut cx = Context {
+ idx: 0,
+ frames: frames,
+ };
+ let result_unwind = unsafe {
+ uw::_Unwind_Backtrace(trace_fn,
+ &mut cx as *mut Context
+ as *mut libc::c_void)
+ };
+ // See libunwind:src/unwind/Backtrace.c for the return values.
+ // No, there is no doc.
+ match result_unwind {
+ // These return codes seem to be benign and need to be ignored for backtraces
+ // to show up properly on all tested platforms.
+ uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+ Ok((cx.idx, BacktraceContext))
}
-
- // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
- // it appears to work fine without it, so we only use
- // FindEnclosingFunction on non-osx platforms. In doing so, we get a
- // slightly more accurate stack trace in the process.
- //
- // This is often because panic involves the last instruction of a
- // function being "call std::rt::begin_unwind", with no ret
- // instructions after it. This means that the return instruction
- // pointer points *outside* of the calling function, and by
- // unwinding it we go back to the original function.
- let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
- ip
- } else {
- unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
- };
-
- // Don't print out the first few frames (they're not user frames)
- cx.idx += 1;
- if cx.idx <= 0 { return uw::_URC_NO_REASON }
- // Don't print ginormous backtraces
- if cx.idx > 100 {
- match write!(cx.writer, " ... <frames omitted>\n") {
- Ok(()) => {}
- Err(e) => { cx.last_error = Some(e); }
- }
- return uw::_URC_FAILURE
+ _ => {
+ Err(io::Error::new(io::ErrorKind::Other,
+ UnwindError(result_unwind)))
}
+ }
+}
- // Once we hit an error, stop trying to print more frames
- if cx.last_error.is_some() { return uw::_URC_FAILURE }
+extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
+ arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
+ let cx = unsafe { &mut *(arg as *mut Context) };
+ let mut ip_before_insn = 0;
+ let mut ip = unsafe {
+ uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
+ };
+ if !ip.is_null() && ip_before_insn == 0 {
+ // this is a non-signaling frame, so `ip` refers to the address
+ // after the calling instruction. account for that.
+ ip = (ip as usize - 1) as *mut _;
+ }
- match print(cx.writer, cx.idx, ip, symaddr) {
- Ok(()) => {}
- Err(e) => { cx.last_error = Some(e); }
- }
+ // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
+ // it appears to work fine without it, so we only use
+ // FindEnclosingFunction on non-osx platforms. In doing so, we get a
+ // slightly more accurate stack trace in the process.
+ //
+ // This is often because panic involves the last instruction of a
+ // function being "call std::rt::begin_unwind", with no ret
+ // instructions after it. This means that the return instruction
+ // pointer points *outside* of the calling function, and by
+ // unwinding it we go back to the original function.
+ let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
+ ip
+ } else {
+ unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
+ };
- // keep going
- uw::_URC_NO_REASON
+ if cx.idx < cx.frames.len() {
+ cx.frames[cx.idx] = Frame {
+ symbol_addr: symaddr,
+ exact_position: ip,
+ };
+ cx.idx += 1;
}
+
+ uw::_URC_NO_REASON
}
ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64};
#[cfg(not(any(target_os = "linux",
target_os = "emscripten",
- target_os = "solaris")))]
+ target_os = "solaris",
+ target_os = "fuchsia")))]
use libc::{readdir_r as readdir64_r};
pub struct File(FileDesc);
entry: dirent64,
root: Arc<PathBuf>,
// We need to store an owned copy of the directory name
- // on Solaris because a) it uses a zero-length array to
- // store the name, b) its lifetime between readdir calls
- // is not guaranteed.
- #[cfg(target_os = "solaris")]
+ // on Solaris and Fuchsia because a) it uses a zero-length
+ // array to store the name, b) its lifetime between readdir
+ // calls is not guaranteed.
+ #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
name: Box<[u8]>
}
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
- #[cfg(target_os = "solaris")]
+ #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
unsafe {
loop {
// Although readdir_r(3) would be a correct function to use here because
- // of the thread safety, on Illumos the readdir(3C) function is safe to use
- // in threaded applications and it is generally preferred over the
- // readdir_r(3C) function.
+ // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
+ // is safe to use in threaded applications and it is generally preferred
+ // over the readdir_r(3C) function.
super::os::set_errno(0);
let entry_ptr = libc::readdir(self.dirp.0);
if entry_ptr.is_null() {
}
}
- #[cfg(not(target_os = "solaris"))]
+ #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
unsafe {
let mut ret = DirEntry {
#[cfg(any(target_os = "android",
target_os = "linux",
target_os = "emscripten",
- target_os = "haiku",
- target_os = "fuchsia"))]
+ target_os = "haiku"))]
fn name_bytes(&self) -> &[u8] {
unsafe {
CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
}
}
- #[cfg(target_os = "solaris")]
+ #[cfg(any(target_os = "solaris",
+ target_os = "fuchsia"))]
fn name_bytes(&self) -> &[u8] {
&*self.name
}
}
/// Sets the platform-specific value of errno
-#[cfg(target_os = "solaris")] // only needed for readdir so far
+#[cfg(any(target_os = "solaris", target_os = "fuchsia"))] // only needed for readdir so far
pub fn set_errno(e: i32) {
unsafe {
*errno_location() = e as c_int
pub fn mx_handle_duplicate(handle: mx_handle_t, rights: mx_rights_t,
out: *const mx_handle_t) -> mx_handle_t;
- pub fn mx_handle_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t,
+ pub fn mx_object_wait_one(handle: mx_handle_t, signals: mx_signals_t, timeout: mx_time_t,
pending: *mut mx_signals_t) -> mx_status_t;
pub fn mx_object_get_info(handle: mx_handle_t, topic: u32, buffer: *mut c_void,
let mut avail: mx_size_t = 0;
unsafe {
- mx_cvt(mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
+ mx_cvt(mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
MX_TIME_INFINITE, ptr::null_mut()))?;
mx_cvt(mx_object_get_info(self.handle.raw(), MX_INFO_PROCESS,
&mut proc_info as *mut _ as *mut libc::c_void,
let mut avail: mx_size_t = 0;
unsafe {
- let status = mx_handle_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
+ let status = mx_object_wait_one(self.handle.raw(), MX_TASK_TERMINATED,
0, ptr::null_mut());
match status {
0 => { }, // Success
+++ /dev/null
-// Copyright 2014 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.
-
-//! As always, windows has something very different than unix, we mainly want
-//! to avoid having to depend too much on libunwind for windows.
-//!
-//! If you google around, you'll find a fair bit of references to built-in
-//! functions to get backtraces on windows. It turns out that most of these are
-//! in an external library called dbghelp. I was unable to find this library
-//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
-//! of it.
-//!
-//! You'll also find that there's a function called CaptureStackBackTrace
-//! mentioned frequently (which is also easy to use), but sadly I didn't have a
-//! copy of that function in my mingw install (maybe it was broken?). Instead,
-//! this takes the route of using StackWalk64 in order to walk the stack.
-
-#![allow(deprecated)] // dynamic_lib
-
-use io::prelude::*;
-
-use io;
-use libc::c_void;
-use mem;
-use ptr;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys::mutex::Mutex;
-
-macro_rules! sym {
- ($lib:expr, $e:expr, $t:ident) => (
- match $lib.symbol($e) {
- Ok(f) => $crate::mem::transmute::<usize, $t>(f),
- Err(..) => return Ok(())
- }
- )
-}
-
-#[cfg(target_env = "msvc")]
-#[path = "printing/msvc.rs"]
-mod printing;
-
-#[cfg(target_env = "gnu")]
-#[path = "printing/gnu.rs"]
-mod printing;
-
-#[cfg(target_env = "gnu")]
-#[path = "backtrace_gnu.rs"]
-pub mod gnu;
-
-type SymInitializeFn =
- unsafe extern "system" fn(c::HANDLE, *mut c_void,
- c::BOOL) -> c::BOOL;
-type SymCleanupFn =
- unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
-
-type StackWalk64Fn =
- unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE,
- *mut c::STACKFRAME64, *mut c::CONTEXT,
- *mut c_void, *mut c_void,
- *mut c_void, *mut c_void) -> c::BOOL;
-
-#[cfg(target_arch = "x86")]
-pub fn init_frame(frame: &mut c::STACKFRAME64,
- ctx: &c::CONTEXT) -> c::DWORD {
- frame.AddrPC.Offset = ctx.Eip as u64;
- frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
- frame.AddrStack.Offset = ctx.Esp as u64;
- frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
- frame.AddrFrame.Offset = ctx.Ebp as u64;
- frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
- c::IMAGE_FILE_MACHINE_I386
-}
-
-#[cfg(target_arch = "x86_64")]
-pub fn init_frame(frame: &mut c::STACKFRAME64,
- ctx: &c::CONTEXT) -> c::DWORD {
- frame.AddrPC.Offset = ctx.Rip as u64;
- frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
- frame.AddrStack.Offset = ctx.Rsp as u64;
- frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
- frame.AddrFrame.Offset = ctx.Rbp as u64;
- frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
- c::IMAGE_FILE_MACHINE_AMD64
-}
-
-struct Cleanup {
- handle: c::HANDLE,
- SymCleanup: SymCleanupFn,
-}
-
-impl Drop for Cleanup {
- fn drop(&mut self) {
- unsafe { (self.SymCleanup)(self.handle); }
- }
-}
-
-pub fn write(w: &mut Write) -> io::Result<()> {
- // According to windows documentation, all dbghelp functions are
- // single-threaded.
- static LOCK: Mutex = Mutex::new();
- unsafe {
- LOCK.lock();
- let res = _write(w);
- LOCK.unlock();
- return res
- }
-}
-
-unsafe fn _write(w: &mut Write) -> io::Result<()> {
- let dbghelp = match DynamicLibrary::open("dbghelp.dll") {
- Ok(lib) => lib,
- Err(..) => return Ok(()),
- };
-
- // Fetch the symbols necessary from dbghelp.dll
- let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn);
- let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn);
- let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn);
-
- // Allocate necessary structures for doing the stack walk
- let process = c::GetCurrentProcess();
- let thread = c::GetCurrentThread();
- let mut context: c::CONTEXT = mem::zeroed();
- c::RtlCaptureContext(&mut context);
- let mut frame: c::STACKFRAME64 = mem::zeroed();
- let image = init_frame(&mut frame, &context);
-
- // Initialize this process's symbols
- let ret = SymInitialize(process, ptr::null_mut(), c::TRUE);
- if ret != c::TRUE { return Ok(()) }
- let _c = Cleanup { handle: process, SymCleanup: SymCleanup };
-
- // And now that we're done with all the setup, do the stack walking!
- // Start from -1 to avoid printing this stack frame, which will
- // always be exactly the same.
- let mut i = -1;
- write!(w, "stack backtrace:\n")?;
- while StackWalk64(image, process, thread, &mut frame, &mut context,
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut()) == c::TRUE {
- let addr = frame.AddrPC.Offset;
- if addr == frame.AddrReturn.Offset || addr == 0 ||
- frame.AddrReturn.Offset == 0 { break }
-
- i += 1;
-
- if i >= 0 {
- printing::print(w, i, addr - 1, process, &dbghelp)?;
- }
- }
-
- Ok(())
-}
--- /dev/null
+// Copyright 2014 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 io;
+use sys::c;
+use libc::c_char;
+use path::PathBuf;
+use fs::{OpenOptions, File};
+use sys::ext::fs::OpenOptionsExt;
+use sys::handle::Handle;
+use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte};
+
+fn query_full_process_image_name() -> io::Result<PathBuf> {
+ unsafe {
+ let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION,
+ c::FALSE,
+ c::GetCurrentProcessId()));
+ fill_utf16_buf(|buf, mut sz| {
+ if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 {
+ 0
+ } else {
+ sz
+ }
+ }, os2path)
+ }
+}
+
+fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> {
+ // We query the current image name, open the file without FILE_SHARE_DELETE so it
+ // can't be moved and then get the current image name again. If the names are the
+ // same than we have successfully locked the file
+ let image_name1 = query_full_process_image_name()?;
+ let file = OpenOptions::new()
+ .read(true)
+ .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE)
+ .open(&image_name1)?;
+ let image_name2 = query_full_process_image_name()?;
+
+ if image_name1 != image_name2 {
+ return Err(io::Error::new(io::ErrorKind::Other,
+ "executable moved while trying to lock it"));
+ }
+
+ Ok((image_name1, file))
+}
+
+// Get the executable filename for libbacktrace
+// This returns the path in the ANSI code page and a File which should remain open
+// for as long as the path should remain valid
+pub fn get_executable_filename() -> io::Result<(Vec<c_char>, File)> {
+ let (executable, file) = lock_and_get_executable_filename()?;
+ let u16_executable = to_u16s(executable.into_os_string())?;
+ Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS,
+ &u16_executable, true)?, file))
+}
--- /dev/null
+// Copyright 2014 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.
+
+//! As always, windows has something very different than unix, we mainly want
+//! to avoid having to depend too much on libunwind for windows.
+//!
+//! If you google around, you'll find a fair bit of references to built-in
+//! functions to get backtraces on windows. It turns out that most of these are
+//! in an external library called dbghelp. I was unable to find this library
+//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent
+//! of it.
+//!
+//! You'll also find that there's a function called CaptureStackBackTrace
+//! mentioned frequently (which is also easy to use), but sadly I didn't have a
+//! copy of that function in my mingw install (maybe it was broken?). Instead,
+//! this takes the route of using StackWalk64 in order to walk the stack.
+
+#![allow(deprecated)] // dynamic_lib
+
+use io;
+use libc::c_void;
+use mem;
+use ptr;
+use sys::c;
+use sys::dynamic_lib::DynamicLibrary;
+use sys_common::backtrace::Frame;
+
+macro_rules! sym {
+ ($lib:expr, $e:expr, $t:ident) => (
+ $lib.symbol($e).map(|f| unsafe {
+ $crate::mem::transmute::<usize, $t>(f)
+ })
+ )
+}
+
+mod printing;
+
+#[cfg(target_env = "gnu")]
+#[path = "backtrace_gnu.rs"]
+pub mod gnu;
+
+pub use self::printing::{resolve_symname, foreach_symbol_fileline};
+
+pub fn unwind_backtrace(frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
+
+ // Fetch the symbols necessary from dbghelp.dll
+ let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
+ let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
+ let StackWalk64 = sym!(dbghelp, "StackWalk64", StackWalk64Fn)?;
+
+ // Allocate necessary structures for doing the stack walk
+ let process = unsafe { c::GetCurrentProcess() };
+ let thread = unsafe { c::GetCurrentThread() };
+ let mut context: c::CONTEXT = unsafe { mem::zeroed() };
+ unsafe { c::RtlCaptureContext(&mut context) };
+ let mut frame: c::STACKFRAME64 = unsafe { mem::zeroed() };
+ let image = init_frame(&mut frame, &context);
+
+ let backtrace_context = BacktraceContext {
+ handle: process,
+ SymCleanup: SymCleanup,
+ dbghelp: dbghelp,
+ };
+
+ // Initialize this process's symbols
+ let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
+ if ret != c::TRUE {
+ return Ok((0, backtrace_context))
+ }
+
+ // And now that we're done with all the setup, do the stack walking!
+ // Start from -1 to avoid printing this stack frame, which will
+ // always be exactly the same.
+ let mut i = 0;
+ unsafe {
+ while i < frames.len() &&
+ StackWalk64(image, process, thread, &mut frame, &mut context,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut()) == c::TRUE
+ {
+ let addr = frame.AddrPC.Offset;
+ if addr == frame.AddrReturn.Offset || addr == 0 ||
+ frame.AddrReturn.Offset == 0 { break }
+
+ frames[i] = Frame {
+ symbol_addr: (addr - 1) as *const c_void,
+ exact_position: (addr - 1) as *const c_void,
+ };
+ i += 1;
+ }
+ }
+
+ Ok((i, backtrace_context))
+}
+
+type SymInitializeFn =
+ unsafe extern "system" fn(c::HANDLE, *mut c_void,
+ c::BOOL) -> c::BOOL;
+type SymCleanupFn =
+ unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
+
+type StackWalk64Fn =
+ unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE,
+ *mut c::STACKFRAME64, *mut c::CONTEXT,
+ *mut c_void, *mut c_void,
+ *mut c_void, *mut c_void) -> c::BOOL;
+
+#[cfg(target_arch = "x86")]
+fn init_frame(frame: &mut c::STACKFRAME64,
+ ctx: &c::CONTEXT) -> c::DWORD {
+ frame.AddrPC.Offset = ctx.Eip as u64;
+ frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ frame.AddrStack.Offset = ctx.Esp as u64;
+ frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ frame.AddrFrame.Offset = ctx.Ebp as u64;
+ frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_I386
+}
+
+#[cfg(target_arch = "x86_64")]
+fn init_frame(frame: &mut c::STACKFRAME64,
+ ctx: &c::CONTEXT) -> c::DWORD {
+ frame.AddrPC.Offset = ctx.Rip as u64;
+ frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ frame.AddrStack.Offset = ctx.Rsp as u64;
+ frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ frame.AddrFrame.Offset = ctx.Rbp as u64;
+ frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_AMD64
+}
+
+pub struct BacktraceContext {
+ handle: c::HANDLE,
+ SymCleanup: SymCleanupFn,
+ // Only used in printing for msvc and not gnu
+ #[allow(dead_code)]
+ dbghelp: DynamicLibrary,
+}
+
+impl Drop for BacktraceContext {
+ fn drop(&mut self) {
+ unsafe { (self.SymCleanup)(self.handle); }
+ }
+}
--- /dev/null
+// Copyright 2014 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.
+
+#[cfg(target_env = "msvc")]
+#[path = "msvc.rs"]
+mod printing;
+
+#[cfg(target_env = "gnu")]
+mod printing {
+ pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+}
+
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
--- /dev/null
+// Copyright 2014 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 ffi::CStr;
+use io;
+use libc::{c_ulong, c_int, c_char};
+use mem;
+use sys::c;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+
+type SymFromAddrFn =
+ unsafe extern "system" fn(c::HANDLE, u64, *mut u64,
+ *mut c::SYMBOL_INFO) -> c::BOOL;
+type SymGetLineFromAddr64Fn =
+ unsafe extern "system" fn(c::HANDLE, u64, *mut u32,
+ *mut c::IMAGEHLP_LINE64) -> c::BOOL;
+
+/// Converts a pointer to symbol to its string value.
+pub fn resolve_symname<F>(frame: Frame,
+ callback: F,
+ context: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ let SymFromAddr = sym!(&context.dbghelp, "SymFromAddr", SymFromAddrFn)?;
+
+ unsafe {
+ let mut info: c::SYMBOL_INFO = mem::zeroed();
+ info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
+ // the struct size in C. the value is different to
+ // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
+ // due to struct alignment.
+ info.SizeOfStruct = 88;
+
+ let mut displacement = 0u64;
+ let ret = SymFromAddr(context.handle,
+ frame.symbol_addr as u64,
+ &mut displacement,
+ &mut info);
+
+ let symname = if ret == c::TRUE {
+ let ptr = info.Name.as_ptr() as *const c_char;
+ CStr::from_ptr(ptr).to_str().ok()
+ } else {
+ None
+ };
+ callback(symname)
+ }
+}
+
+pub fn foreach_symbol_fileline<F>(frame: Frame,
+ mut f: F,
+ context: &BacktraceContext)
+ -> io::Result<bool>
+ where F: FnMut(&[u8], c_int) -> io::Result<()>
+{
+ let SymGetLineFromAddr64 = sym!(&context.dbghelp,
+ "SymGetLineFromAddr64",
+ SymGetLineFromAddr64Fn)?;
+
+ unsafe {
+ let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
+ line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
+
+ let mut displacement = 0u32;
+ let ret = SymGetLineFromAddr64(context.handle,
+ frame.exact_position as u64,
+ &mut displacement,
+ &mut line);
+ if ret == c::TRUE {
+ let name = CStr::from_ptr(line.Filename).to_bytes();
+ f(name, line.LineNumber as c_int)?;
+ }
+ Ok(false)
+ }
+}
+++ /dev/null
-// Copyright 2014 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 io;
-use sys::c;
-use libc::c_char;
-use path::PathBuf;
-use fs::{OpenOptions, File};
-use sys::ext::fs::OpenOptionsExt;
-use sys::handle::Handle;
-use super::super::{fill_utf16_buf, os2path, to_u16s, wide_char_to_multi_byte};
-
-fn query_full_process_image_name() -> io::Result<PathBuf> {
- unsafe {
- let process_handle = Handle::new(c::OpenProcess(c::PROCESS_QUERY_INFORMATION,
- c::FALSE,
- c::GetCurrentProcessId()));
- fill_utf16_buf(|buf, mut sz| {
- if c::QueryFullProcessImageNameW(process_handle.raw(), 0, buf, &mut sz) == 0 {
- 0
- } else {
- sz
- }
- }, os2path)
- }
-}
-
-fn lock_and_get_executable_filename() -> io::Result<(PathBuf, File)> {
- // We query the current image name, open the file without FILE_SHARE_DELETE so it
- // can't be moved and then get the current image name again. If the names are the
- // same than we have successfully locked the file
- let image_name1 = query_full_process_image_name()?;
- let file = OpenOptions::new()
- .read(true)
- .share_mode(c::FILE_SHARE_READ | c::FILE_SHARE_WRITE)
- .open(&image_name1)?;
- let image_name2 = query_full_process_image_name()?;
-
- if image_name1 != image_name2 {
- return Err(io::Error::new(io::ErrorKind::Other,
- "executable moved while trying to lock it"));
- }
-
- Ok((image_name1, file))
-}
-
-// Get the executable filename for libbacktrace
-// This returns the path in the ANSI code page and a File which should remain open
-// for as long as the path should remain valid
-pub fn get_executable_filename() -> io::Result<(Vec<c_char>, File)> {
- let (executable, file) = lock_and_get_executable_filename()?;
- let u16_executable = to_u16s(executable.into_os_string())?;
- Ok((wide_char_to_multi_byte(c::CP_ACP, c::WC_NO_BEST_FIT_CHARS,
- &u16_executable, true)?, file))
-}
+++ /dev/null
-// Copyright 2014 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 io::prelude::*;
-use io;
-use libc::c_void;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys_common::gnu::libbacktrace;
-
-pub fn print(w: &mut Write,
- i: isize,
- addr: u64,
- _process: c::HANDLE,
- _dbghelp: &DynamicLibrary)
- -> io::Result<()> {
- let addr = addr as usize as *mut c_void;
- libbacktrace::print(w, i, addr, addr)
-}
+++ /dev/null
-// Copyright 2014 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 ffi::CStr;
-use io::prelude::*;
-use io;
-use libc::{c_ulong, c_int, c_char, c_void};
-use mem;
-use sys::c;
-use sys::dynamic_lib::DynamicLibrary;
-use sys_common::backtrace::{output, output_fileline};
-
-type SymFromAddrFn =
- unsafe extern "system" fn(c::HANDLE, u64, *mut u64,
- *mut c::SYMBOL_INFO) -> c::BOOL;
-type SymGetLineFromAddr64Fn =
- unsafe extern "system" fn(c::HANDLE, u64, *mut u32,
- *mut c::IMAGEHLP_LINE64) -> c::BOOL;
-
-pub fn print(w: &mut Write,
- i: isize,
- addr: u64,
- process: c::HANDLE,
- dbghelp: &DynamicLibrary)
- -> io::Result<()> {
- unsafe {
- let SymFromAddr = sym!(dbghelp, "SymFromAddr", SymFromAddrFn);
- let SymGetLineFromAddr64 = sym!(dbghelp,
- "SymGetLineFromAddr64",
- SymGetLineFromAddr64Fn);
-
- let mut info: c::SYMBOL_INFO = mem::zeroed();
- info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
- // the struct size in C. the value is different to
- // `size_of::<SYMBOL_INFO>() - MAX_SYM_NAME + 1` (== 81)
- // due to struct alignment.
- info.SizeOfStruct = 88;
-
- let mut displacement = 0u64;
- let ret = SymFromAddr(process, addr, &mut displacement, &mut info);
-
- let name = if ret == c::TRUE {
- let ptr = info.Name.as_ptr() as *const c_char;
- Some(CStr::from_ptr(ptr).to_bytes())
- } else {
- None
- };
-
- output(w, i, addr as usize as *mut c_void, name)?;
-
- // Now find out the filename and line number
- let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
- line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
-
- let mut displacement = 0u32;
- let ret = SymGetLineFromAddr64(process, addr, &mut displacement, &mut line);
- if ret == c::TRUE {
- output_fileline(w,
- CStr::from_ptr(line.Filename).to_bytes(),
- line.LineNumber as c_int,
- false)
- } else {
- Ok(())
- }
- }
-}
#![cfg_attr(target_os = "nacl", allow(dead_code))]
+/// Common code for printing the backtrace in the same way across the different
+/// supported platforms.
+
use env;
use io::prelude::*;
use io;
use libc;
use str;
use sync::atomic::{self, Ordering};
+use path::Path;
+use sys::mutex::Mutex;
+use ptr;
-pub use sys::backtrace::write;
+pub use sys::backtrace::{
+ unwind_backtrace,
+ resolve_symname,
+ foreach_symbol_fileline,
+ BacktraceContext
+};
#[cfg(target_pointer_width = "64")]
pub const HEX_WIDTH: usize = 18;
#[cfg(target_pointer_width = "32")]
pub const HEX_WIDTH: usize = 10;
+/// Represents an item in the backtrace list. See `unwind_backtrace` for how
+/// it is created.
+#[derive(Debug, Copy, Clone)]
+pub struct Frame {
+ /// Exact address of the call that failed.
+ pub exact_position: *const libc::c_void,
+ /// Address of the enclosing function.
+ pub symbol_addr: *const libc::c_void,
+}
+
+/// Max number of frames to print.
+const MAX_NB_FRAMES: usize = 100;
+
+/// Prints the current backtrace.
+pub fn print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+ static LOCK: Mutex = Mutex::new();
+
+ // Use a lock to prevent mixed output in multithreading context.
+ // Some platforms also requires it, like `SymFromAddr` on Windows.
+ unsafe {
+ LOCK.lock();
+ let res = _print(w, format);
+ LOCK.unlock();
+ res
+ }
+}
+
+fn _print(w: &mut Write, format: PrintFormat) -> io::Result<()> {
+ let mut frames = [Frame {
+ exact_position: ptr::null(),
+ symbol_addr: ptr::null(),
+ }; MAX_NB_FRAMES];
+ let (nb_frames, context) = unwind_backtrace(&mut frames)?;
+ let (skipped_before, skipped_after) =
+ filter_frames(&frames[..nb_frames], format, &context);
+ if skipped_before + skipped_after > 0 {
+ writeln!(w, "note: Some details are omitted, \
+ run with `RUST_BACKTRACE=full` for a verbose backtrace.")?;
+ }
+ writeln!(w, "stack backtrace:")?;
+
+ let filtered_frames = &frames[..nb_frames - skipped_after];
+ for (index, frame) in filtered_frames.iter().skip(skipped_before).enumerate() {
+ resolve_symname(*frame, |symname| {
+ output(w, index, *frame, symname, format)
+ }, &context)?;
+ let has_more_filenames = foreach_symbol_fileline(*frame, |file, line| {
+ output_fileline(w, file, line, format)
+ }, &context)?;
+ if has_more_filenames {
+ w.write_all(b" <... and possibly more>")?;
+ }
+ }
+
+ Ok(())
+}
+
+fn filter_frames(frames: &[Frame],
+ format: PrintFormat,
+ context: &BacktraceContext) -> (usize, usize)
+{
+ if format == PrintFormat::Full {
+ return (0, 0);
+ }
+
+ // We want to filter out frames with some prefixes
+ // from both top and bottom of the call stack.
+ static BAD_PREFIXES_TOP: &'static [&'static str] = &[
+ "_ZN3std3sys3imp9backtrace",
+ "ZN3std3sys3imp9backtrace",
+ "std::sys::imp::backtrace",
+ "_ZN3std10sys_common9backtrace",
+ "ZN3std10sys_common9backtrace",
+ "std::sys_common::backtrace",
+ "_ZN3std9panicking",
+ "ZN3std9panicking",
+ "std::panicking",
+ "_ZN4core9panicking",
+ "ZN4core9panicking",
+ "core::panicking",
+ "_ZN4core6result13unwrap_failed",
+ "ZN4core6result13unwrap_failed",
+ "core::result::unwrap_failed",
+ "rust_begin_unwind",
+ "_ZN4drop",
+ "mingw_set_invalid_parameter_handler",
+ ];
+ static BAD_PREFIXES_BOTTOM: &'static [&'static str] = &[
+ "_ZN3std9panicking",
+ "ZN3std9panicking",
+ "std::panicking",
+ "_ZN3std5panic",
+ "ZN3std5panic",
+ "std::panic",
+ "_ZN4core9panicking",
+ "ZN4core9panicking",
+ "core::panicking",
+ "_ZN3std2rt10lang_start",
+ "ZN3std2rt10lang_start",
+ "std::rt::lang_start",
+ "panic_unwind::__rust_maybe_catch_panic",
+ "__rust_maybe_catch_panic",
+ "_rust_maybe_catch_panic",
+ "__libc_start_main",
+ "__rust_try",
+ "_start",
+ "main",
+ "BaseThreadInitThunk",
+ "RtlInitializeExceptionChain",
+ "__scrt_common_main_seh",
+ "_ZN4drop",
+ "mingw_set_invalid_parameter_handler",
+ ];
+
+ let is_good_frame = |frame: Frame, bad_prefixes: &[&str]| {
+ resolve_symname(frame, |symname| {
+ if let Some(mangled_symbol_name) = symname {
+ if !bad_prefixes.iter().any(|s| mangled_symbol_name.starts_with(s)) {
+ return Ok(())
+ }
+ }
+ Err(io::Error::from(io::ErrorKind::Other))
+ }, context).is_ok()
+ };
+
+ let skipped_before = frames.iter().position(|frame| {
+ is_good_frame(*frame, BAD_PREFIXES_TOP)
+ }).unwrap_or(frames.len());
+ let skipped_after = frames[skipped_before..].iter().rev().position(|frame| {
+ is_good_frame(*frame, BAD_PREFIXES_BOTTOM)
+ }).unwrap_or(frames.len() - skipped_before);
+
+ if skipped_before + skipped_after == frames.len() {
+ // Avoid showing completely empty backtraces
+ return (0, 0);
+ }
+
+ (skipped_before, skipped_after)
+}
+
+/// Controls how the backtrace should be formated.
+#[derive(Debug, Copy, Clone, Eq, PartialEq)]
+pub enum PrintFormat {
+ /// Show all the frames with absolute path for files.
+ Full = 2,
+ /// Show only relevant data from the backtrace.
+ Short = 3,
+}
+
// For now logging is turned off by default, and this function checks to see
// whether the magical environment variable is present to see if it's turned on.
-pub fn log_enabled() -> bool {
+pub fn log_enabled() -> Option<PrintFormat> {
static ENABLED: atomic::AtomicIsize = atomic::AtomicIsize::new(0);
match ENABLED.load(Ordering::SeqCst) {
- 1 => return false,
- 2 => return true,
- _ => {}
+ 0 => {},
+ 1 => return None,
+ 2 => return Some(PrintFormat::Full),
+ 3 => return Some(PrintFormat::Short),
+ _ => unreachable!(),
}
let val = match env::var_os("RUST_BACKTRACE") {
- Some(x) => if &x == "0" { 1 } else { 2 },
- None => 1,
+ Some(x) => if &x == "0" {
+ None
+ } else if &x == "full" {
+ Some(PrintFormat::Full)
+ } else {
+ Some(PrintFormat::Short)
+ },
+ None => None,
};
- ENABLED.store(val, Ordering::SeqCst);
- val == 2
+ ENABLED.store(match val {
+ Some(v) => v as isize,
+ None => 1,
+ }, Ordering::SeqCst);
+ val
}
-// These output functions should now be used everywhere to ensure consistency.
-pub fn output(w: &mut Write, idx: isize, addr: *mut libc::c_void,
- s: Option<&[u8]>) -> io::Result<()> {
- write!(w, " {:2}: {:2$?} - ", idx, addr, HEX_WIDTH)?;
- match s.and_then(|s| str::from_utf8(s).ok()) {
- Some(string) => demangle(w, string)?,
- None => write!(w, "<unknown>")?,
+/// Print the symbol of the backtrace frame.
+///
+/// These output functions should now be used everywhere to ensure consistency.
+/// You may want to also use `output_fileline`.
+fn output(w: &mut Write, idx: usize, frame: Frame,
+ s: Option<&str>, format: PrintFormat) -> io::Result<()> {
+ // Remove the `17: 0x0 - <unknown>` line.
+ if format == PrintFormat::Short && frame.exact_position == ptr::null() {
+ return Ok(());
+ }
+ match format {
+ PrintFormat::Full => write!(w,
+ " {:2}: {:2$?} - ",
+ idx,
+ frame.exact_position,
+ HEX_WIDTH)?,
+ PrintFormat::Short => write!(w, " {:2}: ", idx)?,
}
- w.write_all(&['\n' as u8])
+ match s {
+ Some(string) => demangle(w, string, format)?,
+ None => w.write_all(b"<unknown>")?,
+ }
+ w.write_all(b"\n")
}
+/// Print the filename and line number of the backtrace frame.
+///
+/// See also `output`.
#[allow(dead_code)]
-pub fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
- more: bool) -> io::Result<()> {
- let file = str::from_utf8(file).unwrap_or("<unknown>");
+fn output_fileline(w: &mut Write, file: &[u8], line: libc::c_int,
+ format: PrintFormat) -> io::Result<()> {
// prior line: " ##: {:2$} - func"
- write!(w, " {:3$}at {}:{}", "", file, line, HEX_WIDTH)?;
- if more {
- write!(w, " <... and possibly more>")?;
+ w.write_all(b"")?;
+ match format {
+ PrintFormat::Full => write!(w,
+ " {:1$}",
+ "",
+ HEX_WIDTH)?,
+ PrintFormat::Short => write!(w, " ")?,
+ }
+
+ let file = str::from_utf8(file).unwrap_or("<unknown>");
+ let file_path = Path::new(file);
+ let mut already_printed = false;
+ if format == PrintFormat::Short && file_path.is_absolute() {
+ if let Ok(cwd) = env::current_dir() {
+ if let Ok(stripped) = file_path.strip_prefix(&cwd) {
+ if let Some(s) = stripped.to_str() {
+ write!(w, " at ./{}:{}", s, line)?;
+ already_printed = true;
+ }
+ }
+ }
+ }
+ if !already_printed {
+ write!(w, " at {}:{}", file, line)?;
}
- w.write_all(&['\n' as u8])
+
+ w.write_all(b"\n")
}
// Note that this demangler isn't quite as fancy as it could be. We have lots
// of other information in our symbols like hashes, version, type information,
// etc. Additionally, this doesn't handle glue symbols at all.
-pub fn demangle(writer: &mut Write, s: &str) -> io::Result<()> {
+pub fn demangle(writer: &mut Write, s: &str, format: PrintFormat) -> io::Result<()> {
// First validate the symbol. If it doesn't look like anything we're
// expecting, we just print it literally. Note that we must handle non-rust
// symbols because we could have any function in the backtrace.
if !valid {
writer.write_all(s.as_bytes())?;
} else {
+ // remove the `::hfc2edb670e5eda97` part at the end of the symbol.
+ if format == PrintFormat::Short {
+ // The symbol in still mangled.
+ let mut split = inner.rsplitn(2, "17h");
+ match (split.next(), split.next()) {
+ (Some(addr), rest) => {
+ if addr.len() == 16 &&
+ addr.chars().all(|c| c.is_digit(16))
+ {
+ inner = rest.unwrap_or("");
+ }
+ }
+ _ => (),
+ }
+ }
+
let mut first = true;
while !inner.is_empty() {
if !first {
use sys_common;
macro_rules! t { ($a:expr, $b:expr) => ({
let mut m = Vec::new();
- sys_common::backtrace::demangle(&mut m, $a).unwrap();
+ sys_common::backtrace::demangle(&mut m,
+ $a,
+ super::PrintFormat::Full).unwrap();
assert_eq!(String::from_utf8(m).unwrap(), $b);
}) }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use io;
-use io::prelude::*;
use libc;
-use sys_common::backtrace::{output, output_fileline};
-
-pub fn print(w: &mut Write, idx: isize, addr: *mut libc::c_void,
- symaddr: *mut libc::c_void) -> io::Result<()> {
- use ffi::CStr;
- use mem;
- use ptr;
-
- ////////////////////////////////////////////////////////////////////////
- // libbacktrace.h API
- ////////////////////////////////////////////////////////////////////////
- type backtrace_syminfo_callback =
- extern "C" fn(data: *mut libc::c_void,
- pc: libc::uintptr_t,
- symname: *const libc::c_char,
- symval: libc::uintptr_t,
- symsize: libc::uintptr_t);
- type backtrace_full_callback =
- extern "C" fn(data: *mut libc::c_void,
- pc: libc::uintptr_t,
- filename: *const libc::c_char,
- lineno: libc::c_int,
- function: *const libc::c_char) -> libc::c_int;
- type backtrace_error_callback =
- extern "C" fn(data: *mut libc::c_void,
- msg: *const libc::c_char,
- errnum: libc::c_int);
- enum backtrace_state {}
-
- extern {
- fn backtrace_create_state(filename: *const libc::c_char,
- threaded: libc::c_int,
- error: backtrace_error_callback,
- data: *mut libc::c_void)
- -> *mut backtrace_state;
- fn backtrace_syminfo(state: *mut backtrace_state,
- addr: libc::uintptr_t,
- cb: backtrace_syminfo_callback,
- error: backtrace_error_callback,
- data: *mut libc::c_void) -> libc::c_int;
- fn backtrace_pcinfo(state: *mut backtrace_state,
- addr: libc::uintptr_t,
- cb: backtrace_full_callback,
- error: backtrace_error_callback,
- data: *mut libc::c_void) -> libc::c_int;
- }
-
- ////////////////////////////////////////////////////////////////////////
- // helper callbacks
- ////////////////////////////////////////////////////////////////////////
-
- type FileLine = (*const libc::c_char, libc::c_int);
-
- extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
- _errnum: libc::c_int) {
- // do nothing for now
- }
- extern fn syminfo_cb(data: *mut libc::c_void,
- _pc: libc::uintptr_t,
- symname: *const libc::c_char,
- _symval: libc::uintptr_t,
- _symsize: libc::uintptr_t) {
- let slot = data as *mut *const libc::c_char;
- unsafe { *slot = symname; }
- }
- extern fn pcinfo_cb(data: *mut libc::c_void,
- _pc: libc::uintptr_t,
- filename: *const libc::c_char,
- lineno: libc::c_int,
- _function: *const libc::c_char) -> libc::c_int {
- if !filename.is_null() {
- let slot = data as *mut &mut [FileLine];
- let buffer = unsafe {ptr::read(slot)};
-
- // if the buffer is not full, add file:line to the buffer
- // and adjust the buffer for next possible calls to pcinfo_cb.
- if !buffer.is_empty() {
- buffer[0] = (filename, lineno);
- unsafe { ptr::write(slot, &mut buffer[1..]); }
- }
- }
-
- 0
- }
-
- // The libbacktrace API supports creating a state, but it does not
- // support destroying a state. I personally take this to mean that a
- // state is meant to be created and then live forever.
- //
- // I would love to register an at_exit() handler which cleans up this
- // state, but libbacktrace provides no way to do so.
- //
- // With these constraints, this function has a statically cached state
- // that is calculated the first time this is requested. Remember that
- // backtracing all happens serially (one global lock).
- //
- // Things don't work so well on not-Linux since libbacktrace can't track
- // down that executable this is. We at one point used env::current_exe but
- // it turns out that there are some serious security issues with that
- // approach.
- //
- // Specifically, on certain platforms like BSDs, a malicious actor can cause
- // an arbitrary file to be placed at the path returned by current_exe.
- // libbacktrace does not behave defensively in the presence of ill-formed
- // DWARF information, and has been demonstrated to segfault in at least one
- // case. There is no evidence at the moment to suggest that a more carefully
- // constructed file can't cause arbitrary code execution. As a result of all
- // of this, we don't hint libbacktrace with the path to the current process.
- unsafe fn init_state() -> *mut backtrace_state {
- static mut STATE: *mut backtrace_state = ptr::null_mut();
- if !STATE.is_null() { return STATE }
-
- let filename = match ::sys::backtrace::gnu::get_executable_filename() {
- Ok((filename, file)) => {
- // filename is purposely leaked here since libbacktrace requires
- // it to stay allocated permanently, file is also leaked so that
- // the file stays locked
- let filename_ptr = filename.as_ptr();
- mem::forget(filename);
- mem::forget(file);
- filename_ptr
- },
- Err(_) => ptr::null(),
- };
-
- STATE = backtrace_create_state(filename, 0, error_cb,
- ptr::null_mut());
- STATE
- }
-
- ////////////////////////////////////////////////////////////////////////
- // translation
- ////////////////////////////////////////////////////////////////////////
-
- // backtrace errors are currently swept under the rug, only I/O
- // errors are reported
- let state = unsafe { init_state() };
- if state.is_null() {
- return output(w, idx, addr, None)
- }
- let mut data = ptr::null();
- let data_addr = &mut data as *mut *const libc::c_char;
- let ret = unsafe {
- backtrace_syminfo(state, symaddr as libc::uintptr_t,
- syminfo_cb, error_cb,
- data_addr as *mut libc::c_void)
- };
- if ret == 0 || data.is_null() {
- output(w, idx, addr, None)?;
- } else {
- output(w, idx, addr, Some(unsafe { CStr::from_ptr(data).to_bytes() }))?;
- }
+use ffi::CStr;
+use io;
+use mem;
+use ptr;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+
+pub fn foreach_symbol_fileline<F>(frame: Frame,
+ mut f: F,
+ _: &BacktraceContext) -> io::Result<bool>
+where F: FnMut(&[u8], libc::c_int) -> io::Result<()>
+{
// pcinfo may return an arbitrary number of file:line pairs,
// in the order of stack trace (i.e. inlined calls first).
// in order to avoid allocation, we stack-allocate a fixed size of entries.
const FILELINE_SIZE: usize = 32;
let mut fileline_buf = [(ptr::null(), -1); FILELINE_SIZE];
let ret;
- let fileline_count;
- {
+ let fileline_count = {
+ let state = unsafe { init_state() };
let mut fileline_win: &mut [FileLine] = &mut fileline_buf;
let fileline_addr = &mut fileline_win as *mut &mut [FileLine];
ret = unsafe {
- backtrace_pcinfo(state, addr as libc::uintptr_t,
- pcinfo_cb, error_cb,
+ backtrace_pcinfo(state,
+ frame.exact_position as libc::uintptr_t,
+ pcinfo_cb,
+ error_cb,
fileline_addr as *mut libc::c_void)
};
- fileline_count = FILELINE_SIZE - fileline_win.len();
- }
+ FILELINE_SIZE - fileline_win.len()
+ };
if ret == 0 {
- for (i, &(file, line)) in fileline_buf[..fileline_count].iter().enumerate() {
+ for &(file, line) in &fileline_buf[..fileline_count] {
if file.is_null() { continue; } // just to be sure
let file = unsafe { CStr::from_ptr(file).to_bytes() };
- output_fileline(w, file, line, i == FILELINE_SIZE - 1)?;
+ f(file, line)?;
+ }
+ Ok(fileline_count == FILELINE_SIZE)
+ } else {
+ Ok(false)
+ }
+}
+
+/// Converts a pointer to symbol to its string value.
+pub fn resolve_symname<F>(frame: Frame,
+ callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ let symname = {
+ let state = unsafe { init_state() };
+ if state.is_null() {
+ None
+ } else {
+ let mut data = ptr::null();
+ let data_addr = &mut data as *mut *const libc::c_char;
+ let ret = unsafe {
+ backtrace_syminfo(state,
+ frame.symbol_addr as libc::uintptr_t,
+ syminfo_cb,
+ error_cb,
+ data_addr as *mut libc::c_void)
+ };
+ if ret == 0 || data.is_null() {
+ None
+ } else {
+ unsafe {
+ CStr::from_ptr(data).to_str().ok()
+ }
+ }
+ }
+ };
+ callback(symname)
+}
+
+////////////////////////////////////////////////////////////////////////
+// libbacktrace.h API
+////////////////////////////////////////////////////////////////////////
+type backtrace_syminfo_callback =
+extern "C" fn(data: *mut libc::c_void,
+ pc: libc::uintptr_t,
+ symname: *const libc::c_char,
+ symval: libc::uintptr_t,
+ symsize: libc::uintptr_t);
+type backtrace_full_callback =
+extern "C" fn(data: *mut libc::c_void,
+ pc: libc::uintptr_t,
+ filename: *const libc::c_char,
+ lineno: libc::c_int,
+ function: *const libc::c_char) -> libc::c_int;
+type backtrace_error_callback =
+extern "C" fn(data: *mut libc::c_void,
+ msg: *const libc::c_char,
+ errnum: libc::c_int);
+enum backtrace_state {}
+#[link(name = "backtrace", kind = "static")]
+#[cfg(all(not(test), not(cargobuild)))]
+extern {}
+
+extern {
+ fn backtrace_create_state(filename: *const libc::c_char,
+ threaded: libc::c_int,
+ error: backtrace_error_callback,
+ data: *mut libc::c_void)
+ -> *mut backtrace_state;
+ fn backtrace_syminfo(state: *mut backtrace_state,
+ addr: libc::uintptr_t,
+ cb: backtrace_syminfo_callback,
+ error: backtrace_error_callback,
+ data: *mut libc::c_void) -> libc::c_int;
+ fn backtrace_pcinfo(state: *mut backtrace_state,
+ addr: libc::uintptr_t,
+ cb: backtrace_full_callback,
+ error: backtrace_error_callback,
+ data: *mut libc::c_void) -> libc::c_int;
+}
+
+////////////////////////////////////////////////////////////////////////
+// helper callbacks
+////////////////////////////////////////////////////////////////////////
+
+type FileLine = (*const libc::c_char, libc::c_int);
+
+extern fn error_cb(_data: *mut libc::c_void, _msg: *const libc::c_char,
+ _errnum: libc::c_int) {
+ // do nothing for now
+}
+extern fn syminfo_cb(data: *mut libc::c_void,
+ _pc: libc::uintptr_t,
+ symname: *const libc::c_char,
+ _symval: libc::uintptr_t,
+ _symsize: libc::uintptr_t) {
+ let slot = data as *mut *const libc::c_char;
+ unsafe { *slot = symname; }
+}
+extern fn pcinfo_cb(data: *mut libc::c_void,
+ _pc: libc::uintptr_t,
+ filename: *const libc::c_char,
+ lineno: libc::c_int,
+ _function: *const libc::c_char) -> libc::c_int {
+ if !filename.is_null() {
+ let slot = data as *mut &mut [FileLine];
+ let buffer = unsafe {ptr::read(slot)};
+
+ // if the buffer is not full, add file:line to the buffer
+ // and adjust the buffer for next possible calls to pcinfo_cb.
+ if !buffer.is_empty() {
+ buffer[0] = (filename, lineno);
+ unsafe { ptr::write(slot, &mut buffer[1..]); }
}
}
- Ok(())
+ 0
+}
+
+// The libbacktrace API supports creating a state, but it does not
+// support destroying a state. I personally take this to mean that a
+// state is meant to be created and then live forever.
+//
+// I would love to register an at_exit() handler which cleans up this
+// state, but libbacktrace provides no way to do so.
+//
+// With these constraints, this function has a statically cached state
+// that is calculated the first time this is requested. Remember that
+// backtracing all happens serially (one global lock).
+//
+// Things don't work so well on not-Linux since libbacktrace can't track
+// down that executable this is. We at one point used env::current_exe but
+// it turns out that there are some serious security issues with that
+// approach.
+//
+// Specifically, on certain platforms like BSDs, a malicious actor can cause
+// an arbitrary file to be placed at the path returned by current_exe.
+// libbacktrace does not behave defensively in the presence of ill-formed
+// DWARF information, and has been demonstrated to segfault in at least one
+// case. There is no evidence at the moment to suggest that a more carefully
+// constructed file can't cause arbitrary code execution. As a result of all
+// of this, we don't hint libbacktrace with the path to the current process.
+unsafe fn init_state() -> *mut backtrace_state {
+ static mut STATE: *mut backtrace_state = ptr::null_mut();
+ if !STATE.is_null() { return STATE }
+
+ let filename = match ::sys::backtrace::gnu::get_executable_filename() {
+ Ok((filename, file)) => {
+ // filename is purposely leaked here since libbacktrace requires
+ // it to stay allocated permanently, file is also leaked so that
+ // the file stays locked
+ let filename_ptr = filename.as_ptr();
+ mem::forget(filename);
+ mem::forget(file);
+ filename_ptr
+ },
+ Err(_) => ptr::null(),
+ };
+
+ STATE = backtrace_create_state(filename, 0, error_cb,
+ ptr::null_mut());
+ STATE
}
pub struct Builder {
// A name for the thread-to-be, for identification in panic messages
name: Option<String>,
- // The size of the stack for the spawned thread
+ // The size of the stack for the spawned thread in bytes
stack_size: Option<usize>,
}
self
}
- /// Sets the size of the stack for the new thread.
+ /// Sets the size of the stack (in bytes) for the new thread.
+ ///
+ /// The actual stack size may be greater than this value if
+ /// the platform specifies minimal stack size.
///
/// # Examples
///
/// ```
/// use std::thread;
///
- /// let builder = thread::Builder::new().stack_size(10);
+ /// let builder = thread::Builder::new().stack_size(32 * 1024);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stack_size(mut self, size: usize) -> Builder {
#[derive(PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
pub enum ReprAttr {
- ReprAny,
ReprInt(IntType),
ReprExtern,
ReprPacked,
ReprSimd,
}
-impl ReprAttr {
- pub fn is_ffi_safe(&self) -> bool {
- match *self {
- ReprAny => false,
- ReprInt(ity) => ity.is_ffi_safe(),
- ReprExtern => true,
- ReprPacked => false,
- ReprSimd => true,
- }
- }
-}
-
#[derive(Eq, Hash, PartialEq, Debug, RustcEncodable, RustcDecodable, Copy, Clone)]
pub enum IntType {
SignedInt(ast::IntTy),
UnsignedInt(..) => false
}
}
- fn is_ffi_safe(self) -> bool {
- match self {
- SignedInt(ast::IntTy::I8) | UnsignedInt(ast::UintTy::U8) |
- SignedInt(ast::IntTy::I16) | UnsignedInt(ast::UintTy::U16) |
- SignedInt(ast::IntTy::I32) | UnsignedInt(ast::UintTy::U32) |
- SignedInt(ast::IntTy::I64) | UnsignedInt(ast::UintTy::U64) |
- SignedInt(ast::IntTy::I128) | UnsignedInt(ast::UintTy::U128) => true,
- SignedInt(ast::IntTy::Is) | UnsignedInt(ast::UintTy::Us) => false
- }
- }
}
pub trait HasAttrs: Sized {
for<'cx> fn(&'cx mut ExtCtxt, Span, &MetaItem, &Annotatable, &mut FnMut(Annotatable));
/// Represents different kinds of macro invocations that can be resolved.
-#[derive(Clone, Copy, PartialEq, Eq)]
+#[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum MacroKind {
/// A bang macro - foo!()
Bang,
// rustc internal
(active, prelude_import, "1.2.0", None),
- // Allows the definition recursive static items.
- (active, static_recursion, "1.3.0", Some(29719)),
-
// Allows default type parameters to influence type inference.
(active, default_type_parameter_fallback, "1.3.0", Some(27336)),
// `extern "msp430-interrupt" fn()`
(active, abi_msp430_interrupt, "1.16.0", Some(38487)),
+ // Used to identify crates that contain sanitizer runtimes
+ // rustc internal
+ (active, closure_to_fn_coercion, "1.17.0", Some(39817)),
+
// Used to identify crates that contain sanitizer runtimes
// rustc internal
(active, sanitizer_runtime, "1.17.0", None),
(accepted, static_in_const, "1.17.0", Some(35897)),
// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
(accepted, field_init_shorthand, "1.17.0", Some(37340)),
+ // Allows the definition recursive static items.
+ (accepted, static_recursion, "1.17.0", Some(29719)),
);
// If you change this, please modify src/doc/unstable-book as well. You must
// move that documentation into the relevant place in the other docs, and
pub const EXPLAIN_PLACEMENT_IN: &'static str =
"placement-in expression syntax is experimental and subject to change.";
+pub const CLOSURE_TO_FN_COERCION: &'static str =
+ "non-capturing closure to fn coercion is experimental";
+
struct PostExpansionVisitor<'a> {
context: &'a Context<'a>,
}
pub filemap: Rc<syntax_pos::FileMap>,
/// If Some, stop reading the source at this position (inclusive).
pub terminator: Option<BytePos>,
- /// Whether to record new-lines in filemap. This is only necessary the first
- /// time a filemap is lexed. If part of a filemap is being re-lexed, this
- /// should be set to false.
- pub save_new_lines: bool,
+ /// Whether to record new-lines and multibyte chars in filemap.
+ /// This is only necessary the first time a filemap is lexed.
+ /// If part of a filemap is being re-lexed, this should be set to false.
+ pub save_new_lines_and_multibyte: bool,
// cached:
pub peek_tok: token::Token,
pub peek_span: Span,
ch: Some('\n'),
filemap: filemap,
terminator: None,
- save_new_lines: true,
+ save_new_lines_and_multibyte: true,
// dummy values; not read
peek_tok: token::Eof,
peek_span: syntax_pos::DUMMY_SP,
sr
}
+ pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self {
+ let begin = sess.codemap().lookup_byte_offset(span.lo);
+ let end = sess.codemap().lookup_byte_offset(span.hi);
+
+ // Make the range zero-length if the span is invalid.
+ if span.lo > span.hi || begin.fm.start_pos != end.fm.start_pos {
+ span.hi = span.lo;
+ }
+
+ let mut sr = StringReader::new_raw_internal(sess, begin.fm);
+
+ // Seek the lexer to the right byte range.
+ sr.save_new_lines_and_multibyte = false;
+ sr.next_pos = span.lo;
+ sr.terminator = Some(span.hi);
+
+ sr.bump();
+
+ if let Err(_) = sr.advance_token() {
+ sr.emit_fatal_errors();
+ panic!(FatalError);
+ }
+ sr
+ }
+
pub fn ch_is(&self, c: char) -> bool {
self.ch == Some(c)
}
pub fn bump(&mut self) {
let new_pos = self.next_pos;
let new_byte_offset = self.byte_offset(new_pos).to_usize();
- if new_byte_offset < self.source_text.len() {
+ let end = self.terminator.map_or(self.source_text.len(), |t| {
+ self.byte_offset(t).to_usize()
+ });
+ if new_byte_offset < end {
let old_ch_is_newline = self.ch.unwrap() == '\n';
let new_ch = char_at(&self.source_text, new_byte_offset);
let new_ch_len = new_ch.len_utf8();
self.pos = new_pos;
self.next_pos = new_pos + Pos::from_usize(new_ch_len);
if old_ch_is_newline {
- if self.save_new_lines {
+ if self.save_new_lines_and_multibyte {
self.filemap.next_line(self.pos);
}
self.col = CharPos(0);
self.col = self.col + CharPos(1);
}
if new_ch_len > 1 {
- self.filemap.record_multibyte_char(self.pos, new_ch_len);
+ if self.save_new_lines_and_multibyte {
+ self.filemap.record_multibyte_char(self.pos, new_ch_len);
+ }
}
} else {
self.ch = None;
fn visit_expr_post(&mut self, _ex: &'ast Expr) { }
fn visit_ty(&mut self, t: &'ast Ty) { walk_ty(self, t) }
fn visit_generics(&mut self, g: &'ast Generics) { walk_generics(self, g) }
+ fn visit_where_predicate(&mut self, p: &'ast WherePredicate) {
+ walk_where_predicate(self, p)
+ }
fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl, s: Span, _: NodeId) {
walk_fn(self, fk, fd, s)
}
walk_list!(visitor, visit_attribute, &*param.attrs);
}
walk_list!(visitor, visit_lifetime_def, &generics.lifetimes);
- for predicate in &generics.where_clause.predicates {
- match *predicate {
- WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
- ref bounds,
- ref bound_lifetimes,
- ..}) => {
- visitor.visit_ty(bounded_ty);
- walk_list!(visitor, visit_ty_param_bound, bounds);
- walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
- }
- WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
- ref bounds,
- ..}) => {
- visitor.visit_lifetime(lifetime);
- walk_list!(visitor, visit_lifetime, bounds);
- }
- WherePredicate::EqPredicate(WhereEqPredicate{ref lhs_ty,
- ref rhs_ty,
- ..}) => {
- visitor.visit_ty(lhs_ty);
- visitor.visit_ty(rhs_ty);
- }
+ walk_list!(visitor, visit_where_predicate, &generics.where_clause.predicates);
+}
+
+pub fn walk_where_predicate<'a, V: Visitor<'a>>(visitor: &mut V, predicate: &'a WherePredicate) {
+ match *predicate {
+ WherePredicate::BoundPredicate(WhereBoundPredicate{ref bounded_ty,
+ ref bounds,
+ ref bound_lifetimes,
+ ..}) => {
+ visitor.visit_ty(bounded_ty);
+ walk_list!(visitor, visit_ty_param_bound, bounds);
+ walk_list!(visitor, visit_lifetime_def, bound_lifetimes);
+ }
+ WherePredicate::RegionPredicate(WhereRegionPredicate{ref lifetime,
+ ref bounds,
+ ..}) => {
+ visitor.visit_lifetime(lifetime);
+ walk_list!(visitor, visit_lifetime, bounds);
+ }
+ WherePredicate::EqPredicate(WhereEqPredicate{ref lhs_ty,
+ ref rhs_ty,
+ ..}) => {
+ visitor.visit_ty(lhs_ty);
+ visitor.visit_ty(rhs_ty);
}
}
}
for a in type_attrs {
for r in &attr::find_repr_attrs(diagnostic, a) {
repr_type_name = match *r {
- attr::ReprAny | attr::ReprPacked | attr::ReprSimd => continue,
+ attr::ReprPacked | attr::ReprSimd => continue,
attr::ReprExtern => "i32",
attr::ReprInt(attr::SignedInt(ast::IntTy::Is)) => "isize",
}
#[derive(Clone, Copy, PartialEq, Eq)]
-enum NamePadding {
+pub enum NamePadding {
PadNone,
PadOnRight,
}
}
#[derive(Clone)]
-enum TestEvent {
+pub enum TestEvent {
TeFiltered(Vec<TestDesc>),
TeWait(TestDesc, NamePadding),
TeResult(TestDesc, TestResult, Vec<u8>),
pub type MonitorMsg = (TestDesc, TestResult, Vec<u8>);
-fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
+pub fn run_tests<F>(opts: &TestOpts, tests: Vec<TestDescAndFn>, mut callback: F) -> io::Result<()>
where F: FnMut(TestEvent) -> io::Result<()>
{
use std::collections::HashMap;
local_sort(&mut tmp);
let first = 25f64;
let a = percentile_of_sorted(&tmp, first);
- let secound = 50f64;
- let b = percentile_of_sorted(&tmp, secound);
+ let second = 50f64;
+ let b = percentile_of_sorted(&tmp, second);
let third = 75f64;
let c = percentile_of_sorted(&tmp, third);
(a, b, c)
use libc::{c_int, c_void, uintptr_t};
#[repr(C)]
-#[derive(Copy, Clone, PartialEq)]
+#[derive(Debug, Copy, Clone, PartialEq)]
pub enum _Unwind_Reason_Code {
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
--- /dev/null
+# Compiler Test Documentation
+
+In the Rust project, we use a special set of commands embedded in
+comments to test the Rust compiler. There are two groups of commands:
+
+1. Header commands
+2. Error info commands
+
+Both types of commands are inside comments, but header commands should
+be in a comment before any code.
+
+## Summary of Error Info Commands
+
+Error commands specify something about certain lines of the
+program. They tell the test what kind of error and what message you
+are expecting.
+
+* `~`: Associates the following error level and message with the
+ current line
+* `~|`: Associates the following error level and message with the same
+ line as the previous comment
+* `~^`: Associates the following error level and message with the
+ previous line. Each caret (`^`) that you add adds a line to this, so
+ `~^^^^^^^` is seven lines up.
+
+The error levels that you can have are:
+
+1. `ERROR`
+2. `WARNING`
+3. `NOTE`
+4. `HELP` and `SUGGESTION`*
+
+\* **Note**: `SUGGESTION` must follow immediately after `HELP`.
+
+## Summary of Header Commands
+
+Header commands specify something about the entire test file as a
+whole, instead of just a few lines inside the test.
+
+* `ignore-X` where `X` is an architecture, OS or stage will ignore the test accordingly
+* `ignore-pretty` will not compile the pretty-printed test (this is done to test the pretty-printer, but might not always work)
+* `ignore-test` always ignores the test
+* `ignore-lldb` and `ignore-gdb` will skip the debuginfo tests
+* `min-{gdb,lldb}-version`
+* `should-fail` indicates that the test should fail; used for "meta testing",
+ where we test the compiletest program itself to check that it will generate
+ errors in appropriate scenarios. This header is ignored for pretty-printer tests.
+* `gate-test-X` where `X` is a feature marks the test as "gate test" for feature X.
+ Such tests are supposed to ensure that the compiler errors when usage of a gated
+ feature is attempted without the proper `#![feature(X)]` tag.
+ Each unstable lang feature is required to have a gate test.
+
+## Revisions
+
+Certain classes of tests support "revisions" (as of the time of this
+writing, this includes run-pass, compile-fail, run-fail, and
+incremental, though incremental tests are somewhat
+different). Revisions allow a single test file to be used for multiple
+tests. This is done by adding a special header at the top of the file:
+
+```
+// revisions: foo bar baz
+```
+
+This will result in the test being compiled (and tested) three times,
+once with `--cfg foo`, once with `--cfg bar`, and once with `--cfg
+baz`. You can therefore use `#[cfg(foo)]` etc within the test to tweak
+each of these results.
+
+You can also customize headers and expected error messages to a particular
+revision. To do this, add `[foo]` (or `bar`, `baz`, etc) after the `//`
+comment, like so:
+
+```
+// A flag to pass in only for cfg `foo`:
+//[foo]compile-flags: -Z verbose
+
+#[cfg(foo)]
+fn test_foo() {
+ let x: usize = 32_u32; //[foo]~ ERROR mismatched types
+}
+```
+
+Note that not all headers have meaning when customized to a revision.
+For example, the `ignore-test` header (and all "ignore" headers)
+currently only apply to the test as a whole, not to particular
+revisions. The only headers that are intended to really work when
+customized to a revision are error patterns and compiler flags.
fn str(_: &[u8]) {
}
-// CHECK: @trait_borrow(i8* nonnull, void (i8*)** nonnull)
+// CHECK: @trait_borrow(i8* nonnull, void (i8*)** noalias nonnull readonly)
// FIXME #25759 This should also have `nocapture`
#[no_mangle]
fn trait_borrow(_: &Drop) {
}
-// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** nonnull)
+// CHECK: @trait_box(i8* noalias nonnull, void (i8*)** noalias nonnull readonly)
#[no_mangle]
fn trait_box(_: Box<Drop>) {
}
use attr_proc_macro::attr_proc_macro;
-#[derive(FooWithLongNam)]
-//~^ ERROR cannot find derive macro `FooWithLongNam` in this scope
+macro_rules! FooWithLongNam {
+ () => {}
+}
+
+#[derive(FooWithLongNan)]
+//~^ ERROR cannot find derive macro `FooWithLongNan` in this scope
//~^^ HELP did you mean `FooWithLongName`?
struct Foo;
#[attr_proc_macra]
//~^ ERROR cannot find attribute macro `attr_proc_macra` in this scope
+//~^^ HELP did you mean `attr_proc_macro`?
struct Bar;
+#[FooWithLongNan]
+//~^ ERROR cannot find attribute macro `FooWithLongNan` in this scope
+struct Asdf;
+
#[derive(Dlone)]
//~^ ERROR cannot find derive macro `Dlone` in this scope
//~^^ HELP did you mean `Clone`?
//~^^ HELP did you mean `Clona`?
struct B;
-fn main() {}
+#[derive(attr_proc_macra)]
+//~^ ERROR cannot find derive macro `attr_proc_macra` in this scope
+struct C;
+
+fn main() {
+ FooWithLongNama!();
+ //~^ ERROR cannot find macro `FooWithLongNama!` in this scope
+ //~^^ HELP did you mean `FooWithLongNam!`?
+
+ attr_proc_macra!();
+ //~^ ERROR cannot find macro `attr_proc_macra!` in this scope
+
+ Dlona!();
+ //~^ ERROR cannot find macro `Dlona!` in this scope
+}
+++ /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.
-
-enum Foo {
- Q = "32" //~ ERROR E0079
- //~^ expected 'isize' type
-}
-
-fn main() {
-}
// except according to those terms.
enum Enum {
- P = 3, //~ NOTE first use of `3`
+ P = 3, //~ NOTE first use of `3isize`
X = 3,
- //~^ ERROR discriminant value `3` already exists
- //~| NOTE enum already has `3`
+ //~^ ERROR discriminant value `3isize` already exists
+ //~| NOTE enum already has `3isize`
Y = 5
}
//~^ NOTE impl doesn't use types inside crate
//~| NOTE the impl does not reference any types defined in this crate
//~| NOTE define and implement a trait or new type instead
+//~| ERROR the Drop trait may only be implemented on structures
+//~| implementing Drop requires a struct
fn main() {
}
+++ /dev/null
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-const A: [u32; "hello"] = [];
-//~^ ERROR expected `usize` for array length, found string literal [E0306]
-//~| NOTE expected `usize`
-
-const B: [u32; true] = [];
-//~^ ERROR expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
-
-const C: [u32; 0.0] = [];
-//~^ ERROR expected `usize` for array length, found float [E0306]
-//~| NOTE expected `usize`
-
-fn main() {
-}
// ignore-aarch64
// ignore-s390x
// ignore-emscripten
+// ignore-powerpc
#![feature(asm, rustc_attrs)]
// ignore-s390x
// ignore-emscripten
+// ignore-powerpc
#![feature(asm)]
// ignore-aarch64
// ignore-s390x
// ignore-emscripten
+// ignore-powerpc
#![feature(asm, rustc_attrs)]
// ignore-s390x
// ignore-emscripten
+// ignore-powerpc
#![feature(asm)]
// ignore-s390x
// ignore-emscripten
+// ignore-powerpc
#![feature(asm)]
// ignore-s390x
// ignore-emscripten
+// ignore-powerpc
#![feature(asm)]
const ID: usize;
}
-const X: [i32; <i32 as Foo>::ID] = [0, 1, 2]; //~ ERROR E0080
+const X: [i32; <i32 as Foo>::ID] = [0, 1, 2];
+//~^ ERROR the trait bound `i32: Foo` is not satisfied
fn main() {
assert_eq!(1, X);
pub fn test<A: Foo, B: Foo>() {
let _array = [4; <A as Foo>::Y];
//~^ ERROR cannot use an outer type parameter in this context [E0402]
- //~| ERROR constant evaluation error [E0080]
- //~| non-constant path in constant
}
fn main() {
pub fn test<A: Foo, B: Foo>() {
let _array: [u32; <A as Foo>::Y];
//~^ ERROR cannot use an outer type parameter in this context [E0402]
- //~| ERROR constant evaluation error [E0080]
- //~| non-constant path in constant
}
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.
+
+// Ensure that capturing closures are never coerced to fns
+// Especially interesting as non-capturing closures can be.
+
+fn main() {
+ let mut a = 0u8;
+ let foo: fn(u8) -> u8 = |v: u8| { a += v; a };
+ //~^ ERROR mismatched types
+ let b = 0u8;
+ let bar: fn() -> u8 = || { b };
+ //~^ ERROR mismatched types
+ let baz: fn() -> u8 = || { b } as fn() -> u8;
+ //~^ ERROR mismatched types
+ //~^^ ERROR non-scalar cast
+}
impl<A> Foo for A {
//~^ ERROR type parameter `A` must be used as the type parameter for some local type
+ //~| ERROR conflicting implementations of trait `trait_impl_conflict::Foo` for type `isize`
}
fn main() {
trait MyTrait {}
impl MyTrait for .. {}
+//~^ ERROR redundant default implementations of trait `MyTrait`
impl MyTrait for .. {}
-//~^ ERROR redundant default implementations of trait `MyTrait`
trait MySafeTrait {}
impl Sized for MyType {} //~ ERROR E0322
//~^ impl of 'Sized' not allowed
-impl Sized for (MyType, MyType) {} //~ ERROR E0117
+impl Sized for (MyType, MyType) {} //~ ERROR E0322
+//~^ impl of 'Sized' not allowed
+//~| ERROR E0117
impl Sized for &'static NotSync {} //~ ERROR E0322
//~^ impl of 'Sized' not allowed
-impl Sized for [MyType] {} //~ ERROR E0117
+impl Sized for [MyType] {} //~ ERROR E0322
+//~^ impl of 'Sized' not allowed
+//~| ERROR E0117
-impl Sized for &'static [NotSync] {} //~ ERROR E0117
+impl Sized for &'static [NotSync] {} //~ ERROR E0322
+//~^ impl of 'Sized' not allowed
+//~| ERROR E0117
fn main() {
}
#![feature(const_indexing)]
-const FOO: [u32; 3] = [1, 2, 3];
-const BAR: u32 = FOO[5]; // no error, because the error below occurs before regular const eval
+const FOO: [usize; 3] = [1, 2, 3];
+const BAR: usize = FOO[5]; // no error, because the error below occurs before regular const eval
const BLUB: [u32; FOO[4]] = [5, 6];
//~^ ERROR constant evaluation error [E0080]
--- /dev/null
+// Copyright 2014 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.
+
+const A: usize = { 1; 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+
+const B: usize = { { } 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+
+macro_rules! foo {
+ () => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
+}
+const C: usize = { foo!(); 2 };
+
+const D: usize = { let x = 4; 2 };
+//~^ ERROR: blocks in constants are limited to items and tail expressions
+//~^^ ERROR: blocks in constants are limited to items and tail expressions
+
+pub fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-const A: usize = { 1; 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-
-const B: usize = { { } 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-
-macro_rules! foo {
- () => (()) //~ ERROR: blocks in constants are limited to items and tail expressions
-}
-const C: usize = { foo!(); 2 };
-
-const D: usize = { let x = 4; 2 };
-//~^ ERROR: blocks in constants are limited to items and tail expressions
-//~^^ ERROR: blocks in constants are limited to items and tail expressions
-
enum Foo {
Bar = { let x = 1; 3 }
//~^ ERROR: blocks in constants are limited to items and tail expressions
//~^ ERROR: blocks in constants are limited to items and tail expressions
//~^^ ERROR: blocks in constants are limited to items and tail expressions
-pub fn main() {
- let _: Array = [0; { let x = 3; 5 }];
- //~^ ERROR: blocks in constants are limited to items and tail expressions
- //~^^ ERROR: blocks in constants are limited to items and tail expressions
-}
+pub fn main() {}
}
fn main() {
- let _ = [0; f(2)]; //~ ERROR constant evaluation error [E0080]
- //~| non-constant path in constant expression
+ let _ = [0; f(2)];
+ //~^ ERROR calls in constants are limited to constant functions
+ //~| ERROR constant evaluation error [E0080]
+ //~| non-constant path in constant expression
}
const A_I8_T
: [u32; (i8::MAX as i8 + 1u8) as usize]
- //~^ ERROR constant evaluation error [E0080]
+ //~^ ERROR mismatched types
//~| expected i8, found u8
+ //~| ERROR the trait bound `i8: std::ops::Add<u8>` is not satisfied
= [0; (i8::MAX as usize) + 1];
const A_BAD_CHAR_USIZE
: [u32; 5i8 as char as usize]
- //~^ ERROR constant evaluation error
- //~| only `u8` can be cast as `char`, not `i8`
+ //~^ ERROR only `u8` can be cast as `char`, not `i8`
= [0; 5];
fn main() {}
struct S(i32);
const CONSTANT: S = S(0);
-//~^ ERROR E0080
-//~| unimplemented constant expression: tuple struct constructors
enum E {
V = CONSTANT,
- //~^ NOTE: for enum discriminant here
+ //~^ ERROR mismatched types
+ //~| expected isize, found struct `S`
+ //~| NOTE expected type `isize`
+ //~| found type `S`
}
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-const X: usize = 42 && 39; //~ ERROR E0080
- //~| can't do this op on integrals
-const ARR: [i32; X] = [99; 34]; //~ NOTE: for array length here
+const X: usize = 42 && 39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR: [i32; X] = [99; 34];
-const X1: usize = 42 || 39; //~ ERROR E0080
- //~| can't do this op on integrals
-const ARR1: [i32; X1] = [99; 47]; //~ NOTE: for array length here
+const X1: usize = 42 || 39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR1: [i32; X1] = [99; 47];
-const X2: usize = -42 || -39; //~ ERROR E0080
- //~| unary negation of unsigned integer
-const ARR2: [i32; X2] = [99; 18446744073709551607]; //~ NOTE: for array length here
+const X2: usize = -42 || -39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR2: [i32; X2] = [99; 18446744073709551607];
-const X3: usize = -42 && -39; //~ ERROR E0080
- //~| unary negation of unsigned integer
-const ARR3: [i32; X3] = [99; 6]; //~ NOTE: for array length here
+const X3: usize = -42 && -39;
+//~^ ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected bool, found integral variable
+//~| ERROR mismatched types
+//~| expected usize, found bool
+const ARR3: [i32; X3] = [99; 6];
const Y: usize = 42.0 == 42.0;
+//~^ ERROR mismatched types
+//~| expected usize, found bool
const ARRR: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
const Y1: usize = 42.0 >= 42.0;
-const ARRR1: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR1: [i32; Y1] = [99; 1];
const Y2: usize = 42.0 <= 42.0;
-const ARRR2: [i32; Y] = [99; 1];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR2: [i32; Y2] = [99; 1];
const Y3: usize = 42.0 > 42.0;
-const ARRR3: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR3: [i32; Y3] = [99; 0];
const Y4: usize = 42.0 < 42.0;
-const ARRR4: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR4: [i32; Y4] = [99; 0];
const Y5: usize = 42.0 != 42.0;
-const ARRR5: [i32; Y] = [99; 0];
-//~^ ERROR: expected `usize` for array length, found boolean [E0306]
-//~| NOTE expected `usize`
-
+//~^ ERROR mismatched types
+//~| expected usize, found bool
+const ARRR5: [i32; Y5] = [99; 0];
fn main() {
let _ = ARR;
// Test spans of errors
const TUP: (usize,) = 5usize << 64;
-//~^ ERROR E0080
-//~| attempt to shift left with overflow
+//~^ ERROR mismatched types
+//~| expected tuple, found usize
const ARR: [i32; TUP.0] = [];
fn main() {
where T : Trait,
T : Add<T::Item>
//~^ ERROR unsupported cyclic reference between types/traits detected
+ //~| ERROR associated type `Item` not found for `T`
{
data: T
}
trait Foo<X = Box<Foo>> {
//~^ ERROR unsupported cyclic reference
+ //~| ERROR unsupported cyclic reference
}
fn main() { }
// a direct participant in the cycle.
trait A: B {
- //~^ ERROR unsupported cyclic reference
+ //~^ NOTE the cycle begins when computing the supertraits of `B`...
}
trait B: C {
- //~^ ERROR unsupported cyclic reference
+ //~^ NOTE ...which then requires computing the supertraits of `C`...
}
trait C: B { }
//~^ ERROR unsupported cyclic reference
+ //~| cyclic reference
+ //~| NOTE ...which then again requires computing the supertraits of `B`, completing the cycle
fn main() { }
// Here, F is instantiated with $0=uint
let x = foo();
//~^ ERROR: mismatched types
- //~| expected type `usize`
- //~| found type `isize`
//~| NOTE: conflicting type parameter defaults `usize` and `isize`
//~| NOTE: conflicting type parameter defaults `usize` and `isize`
//~| NOTE: ...that was applied to an unconstrained type variable here
//~| NOTE: conflicting type parameter defaults `bool` and `char`
//~| a second default is defined on `default_param_test::bleh`
//~| NOTE: ...that was applied to an unconstrained type variable here
- //~| expected type `bool`
- //~| found type `char`
}
Ok = i8::MAX - 1,
Ok2,
OhNo = 0_u8,
- //~^ ERROR E0080
+ //~^ ERROR mismatched types
//~| expected i8, found u8
}
Ok = u8::MAX - 1,
Ok2,
OhNo = 0_i8,
- //~^ ERROR E0080
+ //~^ ERROR mismatched types
//~| expected u8, found i8
}
Ok = i16::MAX - 1,
Ok2,
OhNo = 0_u16,
- //~^ ERROR E0080
+ //~^ ERROR mismatched types
//~| expected i16, found u16
}
Ok = u16::MAX - 1,
Ok2,
OhNo = 0_i16,
- //~^ ERROR E0080
+ //~^ ERROR mismatched types
//~| expected u16, found i16
}
Ok = i32::MAX - 1,
Ok2,
OhNo = 0_u32,
- //~^ ERROR E0080
+ //~^ ERROR mismatched types
//~| expected i32, found u32
}
Ok = u32::MAX - 1,
Ok2,
OhNo = 0_i32,
- //~^ ERROR E0080
+ //~^ ERROR mismatched types
//~| expected u32, found i32
}
Ok = i64::MAX - 1,
Ok2,
OhNo = 0_u64,
- //~^ ERROR E0080
+ //~^ ERROR mismatched types
//~| expected i64, found u64
}
Ok = u64::MAX - 1,
Ok2,
OhNo = 0_i64,
- //~^ ERROR E0080
+ //~^ ERROR mismatched types
//~| expected u64, found i64
}
enum Eu8 {
Au8 = 23,
Bu8 = 223,
- Cu8 = -23, //~ ERROR E0080
- //~| unary negation of unsigned integer
+ Cu8 = -23,
+ //~^ ERROR cannot apply unary operator `-` to type `u8`
}
#[repr(u16)]
enum Eu16 {
Au16 = 23,
Bu16 = 55555,
- Cu16 = -22333, //~ ERROR E0080
- //~| unary negation of unsigned integer
+ Cu16 = -22333,
+ //~^ ERROR cannot apply unary operator `-` to type `u16`
}
#[repr(u32)]
enum Eu32 {
Au32 = 23,
Bu32 = 3_000_000_000,
- Cu32 = -2_000_000_000, //~ ERROR E0080
- //~| unary negation of unsigned integer
+ Cu32 = -2_000_000_000,
+ //~^ ERROR cannot apply unary operator `-` to type `u32`
}
#[repr(u64)]
enum Eu64 {
Au32 = 23,
Bu32 = 3_000_000_000,
- Cu32 = -2_000_000_000, //~ ERROR E0080
- //~| unary negation of unsigned integer
+ Cu32 = -2_000_000_000,
+ //~^ ERROR cannot apply unary operator `-` to type `u64`
}
// u64 currently allows negative numbers, and i64 allows numbers greater than `1<<63`. This is a
--- /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.
+
+// ignore-stage0: new feature, remove this when SNAP
+// revisions: a b
+
+#[cfg(a)]
+mod a {
+ const FOO: fn(u8) -> u8 = |v: u8| { v };
+ //[a]~^ ERROR non-capturing closure to fn coercion is experimental
+ //[a]~^^ ERROR mismatched types
+
+ const BAR: [fn(&mut u32); 1] = [
+ |v: &mut u32| *v += 1,
+ //[a]~^ ERROR non-capturing closure to fn coercion is experimental
+ //[a]~^^ ERROR mismatched types
+ ];
+}
+
+#[cfg(b)]
+mod b {
+ fn func_specific() -> (fn() -> u32) {
+ || return 42
+ //[b]~^ ERROR non-capturing closure to fn coercion is experimental
+ //[b]~^^ ERROR mismatched types
+ }
+ fn foo() {
+ // Items
+ assert_eq!(func_specific()(), 42);
+ let foo: fn(u8) -> u8 = |v: u8| { v };
+ //[b]~^ ERROR non-capturing closure to fn coercion is experimental
+ //[b]~^^ ERROR mismatched types
+ }
+
+}
+
+
+
+++ /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.
-
-static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-//~^ ERROR recursive static (see issue #29719)
-
-struct StaticDoubleLinked {
- prev: &'static StaticDoubleLinked,
- next: &'static StaticDoubleLinked,
- data: i32,
- head: bool,
-}
-
-static L1: StaticDoubleLinked = StaticDoubleLinked{prev: &L3, next: &L2, data: 1, head: true};
-//~^ ERROR recursive static (see issue #29719)
-//~^^ ERROR recursive static (see issue #29719)
-//~^^^ ERROR recursive static (see issue #29719)
-static L2: StaticDoubleLinked = StaticDoubleLinked{prev: &L1, next: &L3, data: 2, head: false};
-static L3: StaticDoubleLinked = StaticDoubleLinked{prev: &L2, next: &L1, data: 3, head: false};
-
-
-pub fn main() {
- unsafe { assert_eq!(S, *(S as *const *const u8)); }
-
- let mut test_vec = Vec::new();
- let mut cur = &L1;
- loop {
- test_vec.push(cur.data);
- cur = cur.next;
- if cur.head { break }
- }
- assert_eq!(&test_vec, &[1,2,3]);
-
- let mut test_vec = Vec::new();
- let mut cur = &L1;
- loop {
- cur = cur.prev;
- test_vec.push(cur.data);
- if cur.head { break }
- }
- assert_eq!(&test_vec, &[3,2,1]);
-}
--- /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.
+
+struct Test;
+
+impl FnOnce<(u32, u32)> for Test {
+ type Output = u32;
+
+ extern "rust-call" fn call_once(self, (a, b): (u32, u32)) -> u32 {
+ a + b
+ }
+ //~^^^ ERROR rust-call ABI is subject to change (see issue #29625)
+}
+
+fn main() {
+ assert_eq!(Test(1u32, 2u32), 3u32);
+}
struct Heap;
-struct Vec<A = Heap, T>;
+struct Vec<A = Heap, T>(A, T);
//~^ ERROR type parameters with a default must be trailing
-struct Foo<A, B = Vec<C>, C>;
+struct Foo<A, B = Vec<C>, C>(A, B, C);
//~^ ERROR type parameters with a default must be trailing
//~| ERROR type parameters with a default cannot use forward declared identifiers
// except according to those terms.
// Ensure that we get an error and not an ICE for this problematic case.
-struct Foo<T = Option<U>, U = bool>;
+struct Foo<T = Option<U>, U = bool>(T, U);
//~^ ERROR type parameters with a default cannot use forward declared identifiers
fn main() {
let x: Foo;
// independently resolved and only require the concrete
// return type, which can't depend on the obligation.
fn cycle1() -> impl Clone {
+ //~^ ERROR unsupported cyclic reference between types/traits detected
+ //~| cyclic reference
+ //~| NOTE the cycle begins when processing `cycle1`...
+ //~| NOTE ...which then requires processing `cycle1::{{impl-Trait}}`...
+ //~| NOTE ...which then again requires processing `cycle1`, completing the cycle.
send(cycle2().clone());
- //~^ ERROR the trait bound `std::rc::Rc<std::string::String>: std::marker::Send` is not satisfied
- //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::string::String>`
- //~| NOTE `std::rc::Rc<std::string::String>` cannot be sent between threads safely
- //~| NOTE required because it appears within the type `impl std::clone::Clone`
- //~| NOTE required by `send`
Rc::new(Cell::new(5))
}
fn cycle2() -> impl Clone {
+ //~^ NOTE ...which then requires processing `cycle2::{{impl-Trait}}`...
+ //~| NOTE ...which then requires processing `cycle2`...
send(cycle1().clone());
- //~^ ERROR the trait bound `std::rc::Rc<std::cell::Cell<i32>>: std::marker::Send` is not satisfied
- //~| NOTE the trait `std::marker::Send` is not implemented for `std::rc::Rc<std::cell::Cell<i32>>`
- //~| NOTE `std::rc::Rc<std::cell::Cell<i32>>` cannot be sent between threads safely
- //~| NOTE required because it appears within the type `impl std::clone::Clone`
- //~| NOTE required by `send`
Rc::new(String::from("foo"))
}
fn leak(self) -> i32 { self }
}
-trait CheckIfSend: Sized {
- type T: Default;
- fn check(self) -> Self::T { Default::default() }
-}
-impl<T> CheckIfSend for T {
- default type T = ();
-}
-impl<T: Send> CheckIfSend for T {
- type T = bool;
-}
-
fn main() {
let _: u32 = hide(0_u32);
//~^ ERROR mismatched types
//~| found type `<impl Foo as Leak>::T`
//~| expected i32, found associated type
- let _: bool = CheckIfSend::check(hide(0_i32));
- //~^ ERROR mismatched types
- //~| expected type `bool`
- //~| found type `<impl Foo as CheckIfSend>::T`
- //~| expected bool, found associated type
-
let mut x = (hide(0_u32), hide(0_i32));
x = (x.1,
//~^ ERROR mismatched types
fn main() {
fn f(a: [u8; u32::DOESNOTEXIST]) {}
- //~^ ERROR constant evaluation error
- //~| unresolved path in constant expression
+ //~^ ERROR no associated item named `DOESNOTEXIST` found for type `u32`
}
// except according to those terms.
trait t1 : t2 {
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ NOTE the cycle begins when computing the supertraits of `t1`...
+//~| NOTE ...which then requires computing the supertraits of `t2`...
}
trait t2 : t1 {
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ ERROR unsupported cyclic reference between types/traits detected
+//~| cyclic reference
+//~| NOTE ...which then again requires computing the supertraits of `t1`, completing the cycle
}
fn main() { }
enum Foo {
A = 1,
- //~^ NOTE first use of `1`
- //~| NOTE first use of `1`
- //~| NOTE first use of `1`
+ //~^ NOTE first use of `1isize`
+ //~| NOTE first use of `1isize`
+ //~| NOTE first use of `1isize`
B = 1,
- //~^ ERROR discriminant value `1` already exists
- //~| NOTE enum already has `1`
+ //~^ ERROR discriminant value `1isize` already exists
+ //~| NOTE enum already has `1isize`
C = 0,
D,
- //~^ ERROR discriminant value `1` already exists
- //~| NOTE enum already has `1`
+ //~^ ERROR discriminant value `1isize` already exists
+ //~| NOTE enum already has `1isize`
E = N,
- //~^ ERROR discriminant value `1` already exists
- //~| NOTE enum already has `1`
+ //~^ ERROR discriminant value `1isize` already exists
+ //~| NOTE enum already has `1isize`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-pub struct Foo<Bar=Bar>; //~ ERROR E0128
- //~| NOTE defaulted type parameters cannot be forward declared
+pub struct Foo<Bar=Bar>(Bar); //~ ERROR E0128
+ //~| NOTE defaulted type parameters cannot be forward declared
pub struct Baz(Foo);
fn main() {}
trait T : Iterator<Item=Self::Item>
//~^ ERROR unsupported cyclic reference between types/traits detected
+//~| ERROR associated type `Item` not found for `Self`
{}
fn main() {}
}
fn foo<T: Trait<A = T::B>>() { }
-//~^ ERROR: unsupported cyclic reference between types/traits detected
+//~^ ERROR unsupported cyclic reference between types/traits detected
+//~| ERROR associated type `B` not found for `T`
fn main() { }
Pie = 0x1,
Apple = 0x2,
ApplePie = Delicious::Apple as isize | Delicious::PIE as isize,
- //~^ ERROR constant evaluation error
- //~| unresolved path in constant expression
+ //~^ ERROR no associated item named `PIE` found for type `Delicious`
}
const FOO: [u32; u8::MIN as usize] = [];
-//~^ ERROR constant evaluation error
-//~| unresolved path in constant expression
+//~^ ERROR no associated item named `MIN` found for type `u8`
fn main() {}
pub enum SomeEnum {
B = SomeEnum::A,
- //~^ ERROR constant evaluation error
- //~| unresolved path in constant expression
+ //~^ ERROR no associated item named `A` found for type `SomeEnum`
}
fn main() {}
+++ /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.
-
-#![feature(associated_consts)]
-
-struct S;
-
-impl S {
- const N: usize = 3;
-}
-
-static STUFF: [u8; S::N] = [0; S::N];
-//~^ ERROR constant evaluation error
-//~| unresolved path in constant expression
-
-fn main() {}
// Regression test for issue #28586
pub trait Foo {}
-impl Foo for [u8; usize::BYTES] {} //~ ERROR E0080
+impl Foo for [u8; usize::BYTES] {}
+//~^ ERROR no associated item named `BYTES` found for type `usize`
fn main() { }
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(static_recursion)]
-
enum foo { foo_(bar) }
struct bar { x: bar }
//~^ ERROR E0072
#![feature(associated_consts)]
enum Enum<T: Trait> {
- X = Trait::Number, //~ ERROR constant evaluation error
+ X = Trait::Number,
+ //~^ ERROR mismatched types
+ //~| expected isize, found i32
}
trait Trait {
enum Stuff {
Bar = foo
//~^ ERROR attempt to use a non-constant value in a constant
- //~^^ ERROR constant evaluation error
- //~| unresolved path in constant expression
}
- println!("{}", Stuff::Bar);
+ println!("{:?}", Stuff::Bar);
}
fn foo(_: fn(u16) -> ()) {}
//~^ ERROR method `foo` has an incompatible type for trait
//~| NOTE expected u8
+ //~| NOTE expected type `fn(fn(u8))`
fn bar(_: Option<u16>) {}
//~^ ERROR method `bar` has an incompatible type for trait
//~| NOTE expected u8
+ //~| NOTE expected type `fn(std::option::Option<u8>)`
fn baz(_: (u16, u16)) {}
//~^ ERROR method `baz` has an incompatible type for trait
//~| NOTE expected u8
+ //~| NOTE expected type `fn((u8, u16))`
fn qux() -> u16 { 5u16 }
//~^ ERROR method `qux` has an incompatible type for trait
//~| NOTE expected u8
+ //~| NOTE expected type `fn() -> u8`
}
fn main() {}
// Tests that compiling for a target which is not installed will result in a helpful
// error message.
-// compile-flags: --target=s390x-unknown-linux-gnu
-// ignore s390x
+// compile-flags: --target=thumbv6m-none-eabi
+// ignore-arm
// error-pattern:target may not be installed
fn main() { }
--- /dev/null
+// Copyright 2012 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() {
+ 'test_1: while break 'test_1 {}
+ while break {}
+ //~^ ERROR `break` or `continue` with no label
+
+ 'test_2: while let true = break 'test_2 {}
+ while let true = break {}
+ //~^ ERROR `break` or `continue` with no label
+
+ loop { 'test_3: while break 'test_3 {} }
+ loop { while break {} }
+ //~^ ERROR `break` or `continue` with no label
+
+ loop {
+ 'test_4: while break 'test_4 {}
+ break;
+ }
+ loop {
+ while break {}
+ //~^ ERROR `break` or `continue` with no label
+ break;
+ }
+
+ 'test_5: while continue 'test_5 {}
+ while continue {}
+ //~^ ERROR `break` or `continue` with no label
+
+ 'test_6: while let true = continue 'test_6 {}
+ while let true = continue {}
+ //~^ ERROR `break` or `continue` with no label
+
+ loop { 'test_7: while continue 'test_7 {} }
+ loop { while continue {} }
+ //~^ ERROR `break` or `continue` with no label
+
+ loop {
+ 'test_8: while continue 'test_8 {}
+ continue;
+ }
+ loop {
+ while continue {}
+ //~^ ERROR `break` or `continue` with no label
+ continue;
+ }
+}
pub struct Vector<T, D: Dim> {
entries: [T; D::dim()]
//~^ ERROR cannot use an outer type parameter in this context
- //~| ERROR constant evaluation error
}
fn main() {
- let array: [usize; Dim3::dim()] = [0; Dim3::dim()];
+ let array: [usize; Dim3::dim()]
+ //~^ ERROR calls in constants are limited to constant functions
+ //~| ERROR constant evaluation error
+ //~| non-constant path in constant expression
+ = [0; Dim3::dim()];
+ //~^ ERROR calls in constants are limited to constant functions
+ //~| ERROR constant evaluation error
+ //~| non-constant path in constant expression
}
enum Foo {
A = 1i64,
- //~^ ERROR constant evaluation error
+ //~^ ERROR mismatched types
//~| expected isize, found i64
B = 2u8
- //~^ ERROR constant evaluation error
+ //~^ ERROR mismatched types
//~| expected isize, found u8
}
--- /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(never_type)]
+
+mod private {
+ pub struct Private {
+ _bot: !,
+ pub misc: bool,
+ }
+ pub const DATA: Option<Private> = None;
+}
+
+fn main() {
+ match private::DATA {
+ //~^ ERROR non-exhaustive patterns: `Some(Private { misc: true, .. })` not covered
+ None => {}
+ Some(private::Private {
+ misc: false,
+ ..
+ }) => {}
+ }
+}
fn bar(n: isize) {
let _x: [isize; n];
//~^ ERROR attempt to use a non-constant value in a constant [E0435]
- //~| ERROR constant evaluation error [E0080]
}
}
let _x = [0; n];
//~^ ERROR attempt to use a non-constant value in a constant [E0435]
//~| NOTE non-constant used with constant
- //~| NOTE unresolved path in constant expression
- //~| ERROR constant evaluation error [E0080]
}
}
}
}
- // issue #37353
- loop { 'w: while break 'w { } } //~ ERROR use of undeclared label
+ loop { 'w: while break 'w { } }
}
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![feature(associated_type_defaults)]
+
struct S<T = u8>(T);
-trait Tr<T = u8> {}
+trait Tr<T = u8> {
+ type A = ();
+}
impl Tr<Self> for S {} // OK
+impl<T: Tr<Self>> Tr<T> for S {} // OK
+impl<T = Self> Tr<T> for S {} // OK
+impl Tr for S where Self: Copy {} // OK
+impl Tr for S where S<Self>: Copy {} // OK
+impl Tr for S where Self::A: Copy {} // OK
-// FIXME: `Self` cannot be used in bounds because it depends on bounds itself.
-impl<T: Tr<Self>> Tr<T> for S {} //~ ERROR `Self` type is used before it's determined
-impl<T = Self> Tr<T> for S {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S where Self: Copy {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S where S<Self>: Copy {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S where Self::Assoc: Copy {} //~ ERROR `Self` type is used before it's determined
- //~^ ERROR `Self` type is used before it's determined
-impl Tr for Self {} //~ ERROR `Self` type is used before it's determined
-impl Tr for S<Self> {} //~ ERROR `Self` type is used before it's determined
-impl Self {} //~ ERROR `Self` type is used before it's determined
-impl S<Self> {} //~ ERROR `Self` type is used before it's determined
-impl Tr<Self::Assoc> for S {} //~ ERROR `Self` type is used before it's determined
+impl Tr for Self {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Tr for S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Self {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl S<Self> {} //~ ERROR unsupported cyclic reference between types/traits detected
+impl Tr<Self::A> for S {} //~ ERROR unsupported cyclic reference between types/traits detected
fn main() {}
+++ /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.
-
-static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
-//~^ ERROR recursive static
-
-pub fn main() {
- unsafe { assert_eq!(S, *(S as *const *const u8)); }
-}
};
let x: &Void = unsafe { std::mem::uninitialized() };
- let _ = match x {};
- //~^ ERROR non-exhaustive
+ let _ = match x {}; //~ ERROR non-exhaustive
let x: (Void,) = unsafe { std::mem::uninitialized() };
- let _ = match x {};
- //~^ ERROR non-exhaustive
+ let _ = match x {}; //~ ERROR non-exhaustive
let x: [Void; 1] = unsafe { std::mem::uninitialized() };
- let _ = match x {};
- //~^ ERROR non-exhaustive
+ let _ = match x {}; //~ ERROR non-exhaustive
let x: &[Void] = unsafe { std::mem::uninitialized() };
let _ = match x { //~ ERROR non-exhaustive
let Ok(x) = x;
//~^ ERROR refutable
}
-
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_dirty(label="HirBody", cfg="cfail2")]
#[rustc_clean(label="HirBody", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
enum EnumChangeValueCStyleVariant0 {
Variant1,
+
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
Variant2 = 22,
}
--- /dev/null
+// Copyright 2014 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.
+
+// revisions:rpass1 rpass2
+// compile-flags: -Z query-dep-graph
+
+#![rustc_partition_reused(module="__rustc_fallback_codegen_unit", cfg="rpass2")]
+#![feature(rustc_attrs)]
+
+#![crate_type="rlib"]
+pub fn foo<T>() { }
--- /dev/null
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for #39828. If you make use of a module that
+// consists only of generics, no code is generated, just a dummy
+// module. The reduced graph consists of a single node (for that
+// module) with no inputs. Since we only serialize edges, when we
+// reload, we would consider that node dirty since it is not recreated
+// (it is not the target of any edges).
+
+// revisions:rpass1 rpass2
+// aux-build:generic.rs
+
+extern crate generic;
+fn main() { }
// END RUST SOURCE
// START rustc.node4.SimplifyBranches.initial-before.mir
// bb0: {
-// switchInt(const false) -> [0: bb2, otherwise: bb1];
+// switchInt(const false) -> [0u8: bb2, otherwise: bb1];
// }
// END rustc.node4.SimplifyBranches.initial-before.mir
// START rustc.node4.SimplifyBranches.initial-after.mir
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// gate-test-inclusive_range_syntax
+
// Make sure that #![feature(inclusive_range_syntax)] is required.
// #![feature(inclusive_range_syntax, inclusive_range)]
N3[label="local mut x"];
N4[label="stmt let mut x = 10;"];
N5[label="(dummy_node)"];
- N6[label="expr x"];
- N7[label="expr 0"];
- N8[label="expr x > 0"];
- N9[label="expr while x > 0 { x -= 1; }"];
+ N6[label="expr while x > 0 { x -= 1; }"];
+ N7[label="expr x"];
+ N8[label="expr 0"];
+ N9[label="expr x > 0"];
N10[label="expr 1"];
N11[label="expr x"];
N12[label="expr x -= 1"];
N2 -> N3;
N3 -> N4;
N4 -> N5;
- N5 -> N6;
- N6 -> N7;
+ N5 -> N7;
N7 -> N8;
N8 -> N9;
- N8 -> N10;
+ N9 -> N6;
+ N9 -> N10;
N10 -> N11;
N11 -> N12;
N12 -> N13;
N13 -> N14;
N14 -> N5;
- N9 -> N15;
+ N6 -> N15;
N15 -> N16;
N16 -> N1;
}
N9[label="local mut z"];
N10[label="stmt let mut z = 23;"];
N11[label="(dummy_node)"];
- N12[label="expr x"];
- N13[label="expr 0"];
- N14[label="expr x > 0"];
- N15[label="expr while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"];
+ N12[label="expr while x > 0 {\l x -= 1;\l while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l }\l}\l"];
+ N13[label="expr x"];
+ N14[label="expr 0"];
+ N15[label="expr x > 0"];
N16[label="expr 1"];
N17[label="expr x"];
N18[label="expr x -= 1"];
N19[label="stmt x -= 1;"];
N20[label="(dummy_node)"];
- N21[label="expr y"];
- N22[label="expr 0"];
- N23[label="expr y > 0"];
- N24[label="expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"];
+ N21[label="expr while y > 0 {\l y -= 1;\l while z > 0 { z -= 1; }\l if x > 10 { return; \"unreachable\"; }\l}\l"];
+ N22[label="expr y"];
+ N23[label="expr 0"];
+ N24[label="expr y > 0"];
N25[label="expr 1"];
N26[label="expr y"];
N27[label="expr y -= 1"];
N28[label="stmt y -= 1;"];
N29[label="(dummy_node)"];
- N30[label="expr z"];
- N31[label="expr 0"];
- N32[label="expr z > 0"];
- N33[label="expr while z > 0 { z -= 1; }"];
+ N30[label="expr while z > 0 { z -= 1; }"];
+ N31[label="expr z"];
+ N32[label="expr 0"];
+ N33[label="expr z > 0"];
N34[label="expr 1"];
N35[label="expr z"];
N36[label="expr z -= 1"];
N8 -> N9;
N9 -> N10;
N10 -> N11;
- N11 -> N12;
- N12 -> N13;
+ N11 -> N13;
N13 -> N14;
N14 -> N15;
- N14 -> N16;
+ N15 -> N12;
+ N15 -> N16;
N16 -> N17;
N17 -> N18;
N18 -> N19;
N19 -> N20;
- N20 -> N21;
- N21 -> N22;
+ N20 -> N22;
N22 -> N23;
N23 -> N24;
- N23 -> N25;
+ N24 -> N21;
+ N24 -> N25;
N25 -> N26;
N26 -> N27;
N27 -> N28;
N28 -> N29;
- N29 -> N30;
- N30 -> N31;
+ N29 -> N31;
N31 -> N32;
N32 -> N33;
- N32 -> N34;
+ N33 -> N30;
+ N33 -> N34;
N34 -> N35;
N35 -> N36;
N36 -> N37;
N37 -> N38;
N38 -> N29;
- N33 -> N39;
+ N30 -> N39;
N39 -> N40;
N40 -> N41;
N41 -> N42;
N48 -> N49;
N49 -> N50;
N50 -> N20;
- N24 -> N51;
+ N21 -> N51;
N51 -> N11;
- N15 -> N52;
+ N12 -> N52;
N52 -> N53;
N53 -> N1;
}
// Test paths to associated types using the type-parameter-only sugar.
+use std::ops::Deref;
pub trait Foo {
type A;
fn boo(&self) -> Self::A;
+
+ fn baz(_: Self::Target) where Self: Deref {}
}
impl Foo for isize {
--- /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.
+
+// no-prefer-dynamic
+#![crate_type = "staticlib"]
+
+#[no_mangle]
+pub extern "C" fn foo(x:i32) -> i32 { x }
--- /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="rlib"]
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteC(pub u32);
+
+#[derive(Debug, PartialEq)]
+pub struct RemoteG<T>(pub T);
use std::process::Command;
let mut template = Command::new(me);
- template.env("RUST_BACKTRACE", "1");
+ template.env("RUST_BACKTRACE", "full");
let mut i = 0;
loop {
let out = Command::new(me)
- .env("RUST_BACKTRACE", "1")
+ .env("RUST_BACKTRACE", "full")
.arg(i.to_string()).output().unwrap();
let output = str::from_utf8(&out.stdout).unwrap();
let error = str::from_utf8(&out.stderr).unwrap();
}
fn expected(fn_name: &str) -> String {
- format!(" - backtrace::{}", fn_name)
+ format!(" backtrace::{}", fn_name)
}
fn runtest(me: &str) {
let s = str::from_utf8(&out.stderr).unwrap();
assert!(s.contains("stack backtrace") && s.contains(&expected("foo")),
"bad output: {}", s);
+ assert!(s.contains(" 0:"), "the frame number should start at 0");
// Make sure the stack trace is *not* printed
// (Remove RUST_BACKTRACE from our own environment, in case developer
--- /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.
+
+// ignore-stage0: new feature, remove this when SNAP
+
+#![feature(closure_to_fn_coercion)]
+
+const FOO: fn(u8) -> u8 = |v: u8| { v };
+
+const BAR: [fn(&mut u32); 5] = [
+ |_: &mut u32| {},
+ |v: &mut u32| *v += 1,
+ |v: &mut u32| *v += 2,
+ |v: &mut u32| *v += 3,
+ |v: &mut u32| *v += 4,
+];
+fn func_specific() -> (fn() -> u32) {
+ || return 42
+}
+
+fn main() {
+ // Items
+ assert_eq!(func_specific()(), 42);
+ let foo: fn(u8) -> u8 = |v: u8| { v };
+ assert_eq!(foo(31), 31);
+ // Constants
+ assert_eq!(FOO(31), 31);
+ let mut a: u32 = 0;
+ assert_eq!({ BAR[0](&mut a); a }, 0);
+ assert_eq!({ BAR[1](&mut a); a }, 1);
+ assert_eq!({ BAR[2](&mut a); a }, 3);
+ assert_eq!({ BAR[3](&mut a); a }, 6);
+ assert_eq!({ BAR[4](&mut a); a }, 10);
+}
let mut p = Box::new(0);
move |x| *p = x
}
-
-// Cycles should work as the deferred obligations are
-// independently resolved and only require the concrete
-// return type, which can't depend on the obligation.
-fn cycle1() -> impl Clone {
- send(cycle2().clone());
- 5
-}
-
-fn cycle2() -> impl Clone {
- send(cycle1().clone());
- String::from("foo")
-}
fn leak(self) -> T { self }
}
+trait CheckIfSend: Sized {
+ type T: Default;
+ fn check(self) -> Self::T { Default::default() }
+}
+impl<T> CheckIfSend for T {
+ default type T = ();
+}
+impl<T: Send> CheckIfSend for T {
+ type T = bool;
+}
+
fn lucky_seven() -> impl Fn(usize) -> u8 {
let a = [1, 2, 3, 4, 5, 6, 7];
move |i| a[i]
assert_eq!(std::mem::size_of_val(&lucky_seven()), 7);
assert_eq!(Leak::<i32>::leak(hide(5_i32)), 5_i32);
+
+ assert_eq!(CheckIfSend::check(hide(0_i32)), false);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(static_recursion)]
-
// test that autoderef of a type like this does not
// cause compiler to loop. Note that no instances
// of such a type could ever be constructed.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(static_recursion)]
-
// test that autoderef of a type like this does not
// cause compiler to loop. Note that no instances
// of such a type could ever be constructed.
--- /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.
+
+#![feature(associated_consts)]
+
+struct S;
+
+impl S {
+ const N: usize = 3;
+}
+
+static STUFF: [u8; S::N] = [0; S::N];
+
+fn main() {
+ assert_eq!(STUFF, [0; 3]);
+}
--- /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.
+
+// This issue tracks a regression (a new warning) without
+// feature(never_type). When we make that the default, please
+// remove this test.
+
+enum Foo { }
+
+fn make_foo() -> Option<Foo> { None }
+
+#[deny(warnings)]
+fn main() {
+ match make_foo() {
+ None => {},
+ Some(_) => {}
+ }
+}
--- /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.
+
+type Array = [(); ((1 < 2) == false) as usize];
+
+fn main() {
+ let _: Array = [];
+}
--- /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.
+
+// aux-build:issue_39823.rs
+
+extern crate issue_39823;
+use issue_39823::{RemoteC, RemoteG};
+
+#[derive(Debug, PartialEq)]
+struct LocalC(u32);
+
+#[derive(Debug, PartialEq)]
+struct LocalG<T>(T);
+
+fn main() {
+ let virtual_localc : &Fn(_) -> LocalC = &LocalC;
+ assert_eq!(virtual_localc(1), LocalC(1));
+
+ let virtual_localg : &Fn(_) -> LocalG<u32> = &LocalG;
+ assert_eq!(virtual_localg(1), LocalG(1));
+
+ let virtual_remotec : &Fn(_) -> RemoteC = &RemoteC;
+ assert_eq!(virtual_remotec(1), RemoteC(1));
+
+ let virtual_remoteg : &Fn(_) -> RemoteG<u32> = &RemoteG;
+ assert_eq!(virtual_remoteg(1), RemoteG(1));
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -C overflow-checks
+
+use std::panic;
+
+fn main() {
+ let r = panic::catch_unwind(|| {
+ [1, i32::max_value()].iter().sum::<i32>();
+ });
+ assert!(r.is_err());
+
+ let r = panic::catch_unwind(|| {
+ [2, i32::max_value()].iter().product::<i32>();
+ });
+ assert!(r.is_err());
+
+ let r = panic::catch_unwind(|| {
+ [1, i32::max_value()].iter().cloned().sum::<i32>();
+ });
+ assert!(r.is_err());
+
+ let r = panic::catch_unwind(|| {
+ [2, i32::max_value()].iter().cloned().product::<i32>();
+ });
+ assert!(r.is_err());
+}
--- /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.
+
+// aux-build:clibrary.rs
+// compile-flags: -lclibrary
+
+#[link(name = "clibrary", kind = "static")]
+extern "C" {
+ pub fn foo(x:i32) -> i32;
+}
+
+fn main() {
+ unsafe {
+ foo(42);
+ }
+}
assert_eq!(nested_break_value, "hello");
let break_from_while_cond = loop {
- while break {
+ 'inner_loop: while break 'inner_loop {
panic!();
}
break 123;
};
assert_eq!(break_from_while_cond, 123);
+
+ let break_from_while_to_outer = 'outer_loop: loop {
+ while break 'outer_loop 567 {
+ panic!("from_inner");
+ }
+ panic!("from outer");
+ };
+ assert_eq!(break_from_while_to_outer, 567);
}
// except according to those terms.
#![allow(dead_code)]
-#![feature(recover)]
use std::panic::{UnwindSafe, AssertUnwindSafe};
use std::cell::RefCell;
assert::<&RwLock<i32>>();
assert::<Rc<i32>>();
assert::<Arc<i32>>();
+ assert::<Box<[u8]>>();
+
+ trait Trait: UnwindSafe {}
+ assert::<Box<Trait>>();
fn bar<T>() {
assert::<Mutex<T>>();
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(static_recursion)]
-
static mut S: *const u8 = unsafe { &S as *const *const u8 as *const u8 };
struct StaticDoubleLinked {
#![unstable(feature="test", issue="27759")]
// @has issue_27759/unstable/index.html
-// @has - '<code>test</code>'
+// @has - '<code>test </code>'
// @has - '<a href="http://issue_url/27759">#27759</a>'
#[unstable(feature="test", issue="27759")]
pub mod unstable {
// @has issue_27759/unstable/fn.issue.html
- // @has - '<code>test_function</code>'
+ // @has - '<code>test_function </code>'
// @has - '<a href="http://issue_url/1234567890">#1234567890</a>'
#[unstable(feature="test_function", issue="1234567890")]
pub fn issue() {}
// @has issue_32374/struct.T.html '//*[@class="stab deprecated"]' \
// 'Deprecated since 1.0.0: text'
-// @has - '<code>test</code>'
+// @has - '<code>test </code>'
// @has - '<a href="http://issue_url/32374">#32374</a>'
// @matches issue_32374/struct.T.html '//*[@class="stab unstable"]' \
-// '🔬 This is a nightly-only experimental API. \(test #32374\)$'
+// '🔬 This is a nightly-only experimental API. \(test #32374\)$'
#[rustc_deprecated(since = "1.0.0", reason = "text")]
#[unstable(feature = "test", issue = "32374")]
pub struct T;
// @has issue_32374/struct.U.html '//*[@class="stab deprecated"]' \
// 'Deprecated since 1.0.0: deprecated'
// @has issue_32374/struct.U.html '//*[@class="stab unstable"]' \
-// '🔬 This is a nightly-only experimental API. (test #32374)'
+// '🔬 This is a nightly-only experimental API. (test #32374)'
// @has issue_32374/struct.U.html '//details' \
-// '🔬 This is a nightly-only experimental API. (test #32374)'
+// '🔬 This is a nightly-only experimental API. (test #32374)'
// @has issue_32374/struct.U.html '//summary' \
-// '🔬 This is a nightly-only experimental API. (test #32374)'
+// '🔬 This is a nightly-only experimental API. (test #32374)'
// @has issue_32374/struct.U.html '//details/p' \
// 'unstable'
#[rustc_deprecated(since = "1.0.0", reason = "deprecated")]
...
19 | fn foo(x: i16) { }
| ^^^ expected u16, found i16
+ |
+ = note: expected type `fn(u16)`
+ found type `fn(i16)`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/E0053.rs:22:12
...
21 | fn foo(x: i16) { }
| ^^^ expected u16, found i16
+ |
+ = note: expected type `fn(u16)`
+ found type `fn(i16)`
error[E0053]: method `bar` has an incompatible type for trait
--> $DIR/trait-impl-fn-incompatibility.rs:22:28
-error: `Self` type is used before it's determined
+error[E0391]: unsupported cyclic reference between types/traits detected
--> $DIR/issue-23305.rs:15:12
|
15 | impl ToNbt<Self> {}
- | ^^^^
+ | ^^^^ cyclic reference
+ |
+note: the cycle begins when processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`...
+ --> $DIR/issue-23305.rs:15:1
+ |
+15 | impl ToNbt<Self> {}
+ | ^^^^^^^^^^^^^^^^^^^
+ = note: ...which then again requires processing `<impl at $DIR/issue-23305.rs:15:1: 15:20>`, completing the cycle.
error: aborting due to previous error
32 | let b: m::first = m::second; // Misspelled item in module.
| ^^^^^^^^^ did you mean `m::Second`?
-error[E0080]: constant evaluation error
- --> $DIR/levenshtein.rs:30:20
- |
-30 | let v = [0u32; MAXITEM]; // Misspelled constant name.
- | ^^^^^^^ unresolved path in constant expression
-
-error: aborting due to previous error
+error: aborting due to 8 previous errors
15 | impl Copy for Foo { }
| ^^^^
-error[E0204]: the trait `Copy` may not be implemented for this type
- --> $DIR/E0204.rs:27:6
- |
-23 | Bar { x: Vec<u32> },
- | ----------- this field does not implement `Copy`
-...
-27 | impl Copy for EFoo { }
- | ^^^^
-
error[E0204]: the trait `Copy` may not be implemented for this type
--> $DIR/E0204.rs:17:10
|
19 | ty: &'a mut bool,
| ---------------- this field does not implement `Copy`
+error[E0204]: the trait `Copy` may not be implemented for this type
+ --> $DIR/E0204.rs:27:6
+ |
+23 | Bar { x: Vec<u32> },
+ | ----------- this field does not implement `Copy`
+...
+27 | impl Copy for EFoo { }
+ | ^^^^
+
error[E0204]: the trait `Copy` may not be implemented for this type
--> $DIR/E0204.rs:29:10
|
self.package("rust-docs", &mut manifest.pkg, TARGETS);
self.package("rust-src", &mut manifest.pkg, &["*"]);
+ if self.channel == "nightly" {
+ self.package("rust-analysis", &mut manifest.pkg, TARGETS);
+ }
+
let mut pkg = Package {
version: self.cached_version("rust").to_string(),
target: HashMap::new(),
target: target.to_string(),
});
}
+ if self.channel == "nightly" {
+ extensions.push(Component {
+ pkg: "rust-analysis".to_string(),
+ target: target.to_string(),
+ });
+ }
}
extensions.push(Component {
pkg: "rust-src".to_string(),
pkg.target.insert(host.to_string(), Target {
available: true,
url: Some(self.url("rust", host)),
- hash: Some(to_hex(digest.as_ref())),
+ hash: Some(digest),
components: Some(components),
extensions: Some(extensions),
});
self.sign(&dst);
}
}
-
-fn to_hex(digest: &[u8]) -> String {
- let mut ret = String::new();
- for byte in digest {
- ret.push(hex((byte & 0xf0) >> 4));
- ret.push(hex(byte & 0xf));
- }
- return ret;
-
- fn hex(b: u8) -> char {
- match b {
- 0...9 => (b'0' + b) as char,
- _ => (b'a' + b - 10) as char,
- }
- }
-}
fn check_rustdoc_test_option(&self, res: ProcRes) {
let mut other_files = Vec::new();
let mut files: HashMap<String, Vec<usize>> = HashMap::new();
- files.insert(self.testpaths.file.to_str().unwrap().to_owned(),
+ let cwd = env::current_dir().unwrap();
+ files.insert(self.testpaths.file.strip_prefix(&cwd)
+ .unwrap_or(&self.testpaths.file)
+ .to_str()
+ .unwrap()
+ .replace('\\', "/"),
self.get_lines(&self.testpaths.file, Some(&mut other_files)));
for other_file in other_files {
let mut path = self.testpaths.file.clone();
path.set_file_name(&format!("{}.rs", other_file));
- files.insert(path.to_str().unwrap().to_owned(), self.get_lines(&path, None));
+ files.insert(path.strip_prefix(&cwd)
+ .unwrap_or(&path)
+ .to_str()
+ .unwrap()
+ .replace('\\', "/"),
+ self.get_lines(&path, None));
}
let mut tested = 0;
let tmp: Vec<&str> = s.split(" - ").collect();
if tmp.len() == 2 {
let path = tmp[0].rsplit("test ").next().unwrap();
- if let Some(ref mut v) = files.get_mut(path) {
+ if let Some(ref mut v) = files.get_mut(
+ &path.replace('\\', "/")) {
tested += 1;
let mut iter = tmp[1].split("(line ");
iter.next();
});
super::walk_many(&[&path.join("test/compile-fail"),
- &path.join("test/compile-fail-fulldeps")],
+ &path.join("test/compile-fail-fulldeps"),
+ &path.join("test/parse-fail"),],
&mut |path| super::filter_dirs(path),
&mut |file| {
let filename = file.file_name().unwrap().to_string_lossy();
let whitelist = vec![
"abi_ptx", "simd",
"cfg_target_has_atomic",
- "unboxed_closures", "stmt_expr_attributes",
+ "stmt_expr_attributes",
"cfg_target_thread_local", "unwind_attributes",
- "inclusive_range_syntax"
];
// Only check the number of lang features.