depth: 1
submodules: false
+osx_image: xcode8.2
+
matrix:
include:
# Linux builders, all docker images
- env: IMAGE=i686-gnu-nopt
- env: IMAGE=x86_64-freebsd
- env: IMAGE=x86_64-gnu
+ - env: IMAGE=x86_64-gnu-full-bootstrap
- env: IMAGE=x86_64-gnu-cargotest
- env: IMAGE=x86_64-gnu-debug
- env: IMAGE=x86_64-gnu-nopt
- docker history -q rust-ci |
grep -v missing |
xargs docker save |
- gzip -9 > $HOME/docker/rust-ci.tar.gz
+ gzip > $HOME/docker/rust-ci.tar.gz
before_install:
- zcat $HOME/docker/rust-ci.tar.gz | docker load || true
# Install build tools needed for Rust. If you're building a 32-bit compiler,
# then replace "x86_64" below with "i686". If you've already got git, python,
# or CMake installed and in PATH you can remove them from this list. Note
- # that it is important that the `python2` and `cmake` packages **not** used.
- # The build has historically been known to fail with these packages.
+ # that it is important that you do **not** use the 'python2' and 'cmake'
+ # packages from the 'msys2' subsystem. The build has historically been known
+ # to fail with these packages.
$ pacman -S git \
make \
diffutils \
+Version 1.14.0 (2016-12-22)
+===========================
+
+Language
+--------
+
+* [`..` matches multiple tuple fields in enum variants, structs
+ and tuples][36843]. [RFC 1492].
+* [Safe `fn` items can be coerced to `unsafe fn` pointers][37389]
+* [`use *` and `use ::*` both glob-import from the crate root][37367]
+* [It's now possible to call a `Vec<Box<Fn()>>` without explicit
+ dereferencing][36822]
+
+Compiler
+--------
+
+* [Mark enums with non-zero discriminant as non-zero][37224]
+* [Lower-case `static mut` names are linted like other
+ statics and consts][37162]
+* [Fix ICE on some macros in const integer positions
+ (e.g. `[u8; m!()]`)][36819]
+* [Improve error message and snippet for "did you mean `x`"][36798]
+* [Add a panic-strategy field to the target specification][36794]
+* [Include LLVM version in `--version --verbose`][37200]
+
+Compile-time Optimizations
+--------------------------
+
+* [Improve macro expansion performance][37569]
+* [Shrink `Expr_::ExprInlineAsm`][37445]
+* [Replace all uses of SHA-256 with BLAKE2b][37439]
+* [Reduce the number of bytes hashed by `IchHasher`][37427]
+* [Avoid more allocations when compiling html5ever][37373]
+* [Use `SmallVector` in `CombineFields::instantiate`][37322]
+* [Avoid some allocations in the macro parser][37318]
+* [Use a faster deflate setting][37298]
+* [Add `ArrayVec` and `AccumulateVec` to reduce heap allocations
+ during interning of slices][37270]
+* [Optimize `write_metadata`][37267]
+* [Don't process obligation forest cycles when stalled][37231]
+* [Avoid many `CrateConfig` clones][37161]
+* [Optimize `Substs::super_fold_with`][37108]
+* [Optimize `ObligationForest`'s `NodeState` handling][36993]
+* [Speed up `plug_leaks`][36917]
+
+Libraries
+---------
+
+* [`println!()`, with no arguments, prints newline][36825].
+ Previously, an empty string was required to achieve the same.
+* [`Wrapping` impls standard binary and unary operators, as well as
+ the `Sum` and `Product` iterators][37356]
+* [Implement `From<Cow<str>> for String` and `From<Cow<[T]>> for
+ Vec<T>`][37326]
+* [Improve `fold` performance for `chain`, `cloned`, `map`, and
+ `VecDeque` iterators][37315]
+* [Improve `SipHasher` performance on small values][37312]
+* [Add Iterator trait TrustedLen to enable better FromIterator /
+ Extend][37306]
+* [Expand `.zip()` specialization to `.map()` and `.cloned()`][37230]
+* [`ReadDir` implements `Debug`][37221]
+* [Implement `RefUnwindSafe` for atomic types][37178]
+* [Specialize `Vec::extend` to `Vec::extend_from_slice`][37094]
+* [Avoid allocations in `Decoder::read_str`][37064]
+* [`io::Error` implements `From<io::ErrorKind>`][37037]
+* [Impl `Debug` for raw pointers to unsized data][36880]
+* [Don't reuse `HashMap` random seeds][37470]
+* [The internal memory layout of `HashMap` is more cache-friendly, for
+ significant improvements in some operations][36692]
+* [`HashMap` uses less memory on 32-bit architectures][36595]
+* [Impl `Add<{str, Cow<str>}>` for `Cow<str>`][36430]
+
+Cargo
+-----
+
+* [Expose rustc cfg values to build scripts][cargo/3243]
+* [Allow cargo to work with read-only `CARGO_HOME`][cargo/3259]
+* [Fix passing --features when testing multiple packages][cargo/3280]
+* [Use a single profile set per workspace][cargo/3249]
+* [Load `replace` sections from lock files][cargo/3220]
+* [Ignore `panic` configuration for test/bench profiles][cargo/3175]
+
+Tooling
+-------
+
+* [rustup is the recommended Rust installation method][1.14rustup]
+* This release includes host (rustc) builds for Linux on MIPS, PowerPC, and
+ S390x. These are [tier 2] platforms and may have major defects. Follow the
+ instructions on the website to install, or add the targets to an existing
+ installation with `rustup target add`. The new target triples are:
+ - `mips-unknown-linux-gnu`
+ - `mipsel-unknown-linux-gnu`
+ - `mips64-unknown-linux-gnuabi64`
+ - `mips64el-unknown-linux-gnuabi64 `
+ - `powerpc-unknown-linux-gnu`
+ - `powerpc64-unknown-linux-gnu`
+ - `powerpc64le-unknown-linux-gnu`
+ - `s390x-unknown-linux-gnu `
+* This release includes target (std) builds for ARM Linux running MUSL
+ libc. These are [tier 2] platforms and may have major defects. Add the
+ following triples to an existing rustup installation with `rustup target add`:
+ - `arm-unknown-linux-musleabi`
+ - `arm-unknown-linux-musleabihf`
+ - `armv7-unknown-linux-musleabihf`
+* This release includes [experimental support for WebAssembly][1.14wasm], via
+ the `wasm32-unknown-emscripten` target. This target is known to have major
+ defects. Please test, report, and fix.
+* rustup no longer installs documentation by default. Run `rustup
+ component add rust-docs` to install.
+* [Fix line stepping in debugger][37310]
+* [Enable line number debuginfo in releases][37280]
+
+Misc
+----
+
+* [Disable jemalloc on aarch64/powerpc/mips][37392]
+* [Add support for Fuchsia OS][37313]
+* [Detect local-rebuild by only MAJOR.MINOR version][37273]
+
+Compatibility Notes
+-------------------
+
+* [A number of forward-compatibility lints used by the compiler
+ to gradually introduce language changes have been converted
+ to deny by default][36894]:
+ - ["use of inaccessible extern crate erroneously allowed"][36886]
+ - ["type parameter default erroneously allowed in invalid location"][36887]
+ - ["detects super or self keywords at the beginning of global path"][36888]
+ - ["two overlapping inherent impls define an item with the same name
+ were erroneously allowed"][36889]
+ - ["floating-point constants cannot be used in patterns"][36890]
+ - ["constants of struct or enum type can only be used in a pattern if
+ the struct or enum has `#[derive(PartialEq, Eq)]`"][36891]
+ - ["lifetimes or labels named `'_` were erroneously allowed"][36892]
+* [Prohibit patterns in trait methods without bodies][37378]
+* [The atomic `Ordering` enum may not be matched exhaustively][37351]
+* [Future-proofing `#[no_link]` breaks some obscure cases][37247]
+* [The `$crate` macro variable is accepted in fewer locations][37213]
+* [Impls specifying extra region requirements beyond the trait
+ they implement are rejected][37167]
+* [Enums may not be unsized][37111]. Unsized enums are intended to
+ work but never have. For now they are forbidden.
+* [Enforce the shadowing restrictions from RFC 1560 for today's macros][36767]
+
+[tier 2]: https://forge.rust-lang.org/platform-support.html
+[1.14rustup]: https://internals.rust-lang.org/t/beta-testing-rustup-rs/3316/204
+[1.14wasm]: https://users.rust-lang.org/t/compiling-to-the-web-with-rust-and-emscripten/7627
+[36430]: https://github.com/rust-lang/rust/pull/36430
+[36595]: https://github.com/rust-lang/rust/pull/36595
+[36595]: https://github.com/rust-lang/rust/pull/36595
+[36692]: https://github.com/rust-lang/rust/pull/36692
+[36767]: https://github.com/rust-lang/rust/pull/36767
+[36794]: https://github.com/rust-lang/rust/pull/36794
+[36798]: https://github.com/rust-lang/rust/pull/36798
+[36819]: https://github.com/rust-lang/rust/pull/36819
+[36822]: https://github.com/rust-lang/rust/pull/36822
+[36825]: https://github.com/rust-lang/rust/pull/36825
+[36843]: https://github.com/rust-lang/rust/pull/36843
+[36880]: https://github.com/rust-lang/rust/pull/36880
+[36886]: https://github.com/rust-lang/rust/issues/36886
+[36887]: https://github.com/rust-lang/rust/issues/36887
+[36888]: https://github.com/rust-lang/rust/issues/36888
+[36889]: https://github.com/rust-lang/rust/issues/36889
+[36890]: https://github.com/rust-lang/rust/issues/36890
+[36891]: https://github.com/rust-lang/rust/issues/36891
+[36892]: https://github.com/rust-lang/rust/issues/36892
+[36894]: https://github.com/rust-lang/rust/pull/36894
+[36917]: https://github.com/rust-lang/rust/pull/36917
+[36993]: https://github.com/rust-lang/rust/pull/36993
+[37037]: https://github.com/rust-lang/rust/pull/37037
+[37064]: https://github.com/rust-lang/rust/pull/37064
+[37094]: https://github.com/rust-lang/rust/pull/37094
+[37108]: https://github.com/rust-lang/rust/pull/37108
+[37111]: https://github.com/rust-lang/rust/pull/37111
+[37161]: https://github.com/rust-lang/rust/pull/37161
+[37162]: https://github.com/rust-lang/rust/pull/37162
+[37167]: https://github.com/rust-lang/rust/pull/37167
+[37178]: https://github.com/rust-lang/rust/pull/37178
+[37200]: https://github.com/rust-lang/rust/pull/37200
+[37213]: https://github.com/rust-lang/rust/pull/37213
+[37221]: https://github.com/rust-lang/rust/pull/37221
+[37224]: https://github.com/rust-lang/rust/pull/37224
+[37230]: https://github.com/rust-lang/rust/pull/37230
+[37231]: https://github.com/rust-lang/rust/pull/37231
+[37247]: https://github.com/rust-lang/rust/pull/37247
+[37267]: https://github.com/rust-lang/rust/pull/37267
+[37270]: https://github.com/rust-lang/rust/pull/37270
+[37273]: https://github.com/rust-lang/rust/pull/37273
+[37280]: https://github.com/rust-lang/rust/pull/37280
+[37298]: https://github.com/rust-lang/rust/pull/37298
+[37306]: https://github.com/rust-lang/rust/pull/37306
+[37310]: https://github.com/rust-lang/rust/pull/37310
+[37312]: https://github.com/rust-lang/rust/pull/37312
+[37313]: https://github.com/rust-lang/rust/pull/37313
+[37315]: https://github.com/rust-lang/rust/pull/37315
+[37318]: https://github.com/rust-lang/rust/pull/37318
+[37322]: https://github.com/rust-lang/rust/pull/37322
+[37326]: https://github.com/rust-lang/rust/pull/37326
+[37351]: https://github.com/rust-lang/rust/pull/37351
+[37356]: https://github.com/rust-lang/rust/pull/37356
+[37367]: https://github.com/rust-lang/rust/pull/37367
+[37373]: https://github.com/rust-lang/rust/pull/37373
+[37378]: https://github.com/rust-lang/rust/pull/37378
+[37389]: https://github.com/rust-lang/rust/pull/37389
+[37392]: https://github.com/rust-lang/rust/pull/37392
+[37427]: https://github.com/rust-lang/rust/pull/37427
+[37439]: https://github.com/rust-lang/rust/pull/37439
+[37445]: https://github.com/rust-lang/rust/pull/37445
+[37470]: https://github.com/rust-lang/rust/pull/37470
+[37569]: https://github.com/rust-lang/rust/pull/37569
+[RFC 1492]: https://github.com/rust-lang/rfcs/blob/master/text/1492-dotdot-in-patterns.md
+[cargo/3175]: https://github.com/rust-lang/cargo/pull/3175
+[cargo/3220]: https://github.com/rust-lang/cargo/pull/3220
+[cargo/3243]: https://github.com/rust-lang/cargo/pull/3243
+[cargo/3249]: https://github.com/rust-lang/cargo/pull/3249
+[cargo/3259]: https://github.com/rust-lang/cargo/pull/3259
+[cargo/3280]: https://github.com/rust-lang/cargo/pull/3280
+
+
Version 1.13.0 (2016-11-10)
===========================
opt_nosave clang 0 "prefer clang to gcc for building the runtime"
opt_nosave jemalloc 1 "build liballoc with jemalloc"
opt elf-tls 1 "elf thread local storage on platforms where supported"
+opt full-bootstrap 0 "build three compilers instead of two"
valopt_nosave prefix "/usr/local" "set installation prefix"
valopt_nosave local-rust-root "/usr/local" "set prefix for local rust binary"
esac
putvar CFG_LLDB_PYTHON
+# Do some sanity checks if running on buildbot
+# (these env vars are set by rust-buildbot)
+if [ -n "$RUST_DIST_SERVER" -a -n "$ALLOW_NONZERO_RLIMIT_CORE" ]; then
+ # Frequently the llvm submodule directory is broken by the build
+ # being killed
+ llvm_lock="${CFG_SRC_DIR}/.git/modules/src/llvm/index.lock"
+ if [ -e "$llvm_lock" ]; then
+ step_msg "removing $llvm_lock"
+ rm -f "$llvm_lock"
+ fi
+fi
+
step_msg "looking for target specific programs"
probe CFG_ADB adb
--- /dev/null
+# rustbuild-only target
```
The `--incremental` flag will store incremental compilation artifacts
-in `build/stage0-incremental`. Note that we only use incremental
+in `build/<host>/stage0-incremental`. Note that we only use incremental
compilation for the stage0 -> stage1 compilation -- this is because
the stage1 compiler is changing, and we don't try to cache and reuse
incremental artifacts across different versions of the compiler. For
("RUSTC_REAL", "RUSTC_LIBDIR")
};
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 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));
if let Some(target) = target {
// The stage0 compiler has a special sysroot distinct from what we
// actually downloaded, so we just always pass the `--sysroot` option.
- cmd.arg("--sysroot").arg(env::var_os("RUSTC_SYSROOT").expect("RUSTC_SYSROOT was not set"));
+ cmd.arg("--sysroot").arg(sysroot);
// When we build Rust dylibs they're all intended for intermediate
// usage, so make sure we pass the -Cprefer-dynamic flag instead of
let rustdoc = env::var_os("RUSTDOC_REAL").expect("RUSTDOC_REAL was not set");
let libdir = env::var_os("RUSTC_LIBDIR").expect("RUSTC_LIBDIR was not set");
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 dylib_path = bootstrap::util::dylib_path();
dylib_path.insert(0, PathBuf::from(libdir));
.arg(format!("stage{}", stage))
.arg("--cfg")
.arg("dox")
+ .arg("--sysroot")
+ .arg(sysroot)
.env(bootstrap::util::dylib_path_var(),
env::join_paths(&dylib_path).unwrap());
std::process::exit(match cmd.status() {
println!("{} {} stage{} ({} -> {})", test_kind, name, compiler.stage,
compiler.host, target);
+ // If we're not doing a full bootstrap but we're testing a stage2 version of
+ // libstd, then what we're actually testing is the libstd produced in
+ // stage1. Reflect that here by updating the compiler that we're working
+ // with automatically.
+ let compiler = if build.force_use_stage1(compiler, target) {
+ Compiler::new(1, compiler.host)
+ } else {
+ compiler.clone()
+ };
+
// Build up the base `cargo test` command.
//
// Pass in some standard flags then iterate over the graph we've discovered
// in `cargo metadata` with the maps above and figure out what `-p`
// arguments need to get passed.
- let mut cargo = build.cargo(compiler, mode, target, test_kind.subcommand());
+ let mut cargo = build.cargo(&compiler, mode, target, test_kind.subcommand());
cargo.arg("--manifest-path")
.arg(build.src.join(path).join("Cargo.toml"))
.arg("--features").arg(features);
// Note that to run the compiler we need to run with the *host* libraries,
// but our wrapper scripts arrange for that to be the case anyway.
let mut dylib_path = dylib_path();
- dylib_path.insert(0, build.sysroot_libdir(compiler, target));
+ dylib_path.insert(0, build.sysroot_libdir(&compiler, target));
cargo.env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
if target.contains("android") {
if target.contains("android") {
build.run(&mut cargo);
- krate_android(build, compiler, target, mode);
+ krate_android(build, &compiler, target, mode);
} else if target.contains("emscripten") {
build.run(&mut cargo);
- krate_emscripten(build, compiler, target, mode);
+ krate_emscripten(build, &compiler, target, mode);
} else {
cargo.args(&build.flags.cmd.test_args());
build.run(&mut cargo);
/// This will build the standard library for a particular stage of the build
/// using the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
-pub fn std<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
- println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
- compiler.host, target);
-
+pub fn std(build: &Build, target: &str, compiler: &Compiler) {
let libdir = build.sysroot_libdir(compiler, target);
let _ = fs::remove_dir_all(&libdir);
t!(fs::create_dir_all(&libdir));
+ println!("Building stage{} std artifacts ({} -> {})", compiler.stage,
+ compiler.host, target);
+
// Some platforms have startup objects that may be required to produce the
// libstd dynamic library, for example.
build_startup_objects(build, target, &libdir);
build.run(&mut cargo);
update_mtime(&libstd_stamp(build, &compiler, target));
- std_link(build, target, compiler.stage, compiler.host);
}
/// Link all libstd rlibs/dylibs into the sysroot location.
///
-/// Links those artifacts generated in the given `stage` for `target` produced
-/// by `compiler` into `host`'s sysroot.
+/// Links those artifacts generated by `compiler` to a the `stage` compiler's
+/// sysroot for the specified `host` and `target`.
+///
+/// Note that this assumes that `compiler` has already generated the libstd
+/// libraries for `target`, and this method will find them in the relevant
+/// output directory.
pub fn std_link(build: &Build,
- target: &str,
- stage: u32,
- host: &str) {
- let compiler = Compiler::new(stage, &build.config.build);
- let target_compiler = Compiler::new(compiler.stage, host);
+ compiler: &Compiler,
+ target_compiler: &Compiler,
+ target: &str) {
+ println!("Copying stage{} std from stage{} ({} -> {} / {})",
+ target_compiler.stage,
+ compiler.stage,
+ compiler.host,
+ target_compiler.host,
+ target);
let libdir = build.sysroot_libdir(&target_compiler, target);
let out_dir = build.cargo_out(&compiler, Mode::Libstd, target);
- // If we're linking one compiler host's output into another, then we weren't
- // called from the `std` method above. In that case we clean out what's
- // already there.
- if host != compiler.host {
- let _ = fs::remove_dir_all(&libdir);
- t!(fs::create_dir_all(&libdir));
- }
+ t!(fs::create_dir_all(&libdir));
add_to_sysroot(&out_dir, &libdir);
if target.contains("musl") && !target.contains("mips") {
/// This will build libtest and supporting libraries for a particular stage of
/// the build using the `compiler` targeting the `target` architecture. The
/// artifacts created will also be linked into the sysroot directory.
-pub fn test<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
+pub fn test(build: &Build, target: &str, compiler: &Compiler) {
println!("Building stage{} test artifacts ({} -> {})", compiler.stage,
compiler.host, target);
let out_dir = build.cargo_out(compiler, Mode::Libtest, target);
.arg(build.src.join("src/rustc/test_shim/Cargo.toml"));
build.run(&mut cargo);
update_mtime(&libtest_stamp(build, compiler, target));
- test_link(build, target, compiler.stage, compiler.host);
}
-/// Link all libtest rlibs/dylibs into the sysroot location.
-///
-/// Links those artifacts generated in the given `stage` for `target` produced
-/// by `compiler` into `host`'s sysroot.
+/// Same as `std_link`, only for libtest
pub fn test_link(build: &Build,
- target: &str,
- stage: u32,
- host: &str) {
- let compiler = Compiler::new(stage, &build.config.build);
- let target_compiler = Compiler::new(compiler.stage, host);
+ compiler: &Compiler,
+ target_compiler: &Compiler,
+ target: &str) {
let libdir = build.sysroot_libdir(&target_compiler, target);
let out_dir = build.cargo_out(&compiler, Mode::Libtest, target);
add_to_sysroot(&out_dir, &libdir);
/// This will build the compiler for a particular stage of the build using
/// the `compiler` targeting the `target` architecture. The artifacts
/// created will also be linked into the sysroot directory.
-pub fn rustc<'a>(build: &'a Build, target: &str, compiler: &Compiler<'a>) {
+pub fn rustc(build: &Build, target: &str, compiler: &Compiler) {
println!("Building stage{} compiler artifacts ({} -> {})",
compiler.stage, compiler.host, target);
cargo.env("CFG_DEFAULT_AR", s);
}
build.run(&mut cargo);
-
- rustc_link(build, target, compiler.stage, compiler.host);
}
-/// Link all librustc rlibs/dylibs into the sysroot location.
-///
-/// Links those artifacts generated in the given `stage` for `target` produced
-/// by `compiler` into `host`'s sysroot.
+/// Same as `std_link`, only for librustc
pub fn rustc_link(build: &Build,
- target: &str,
- stage: u32,
- host: &str) {
- let compiler = Compiler::new(stage, &build.config.build);
- let target_compiler = Compiler::new(compiler.stage, host);
+ compiler: &Compiler,
+ target_compiler: &Compiler,
+ target: &str) {
let libdir = build.sysroot_libdir(&target_compiler, target);
let out_dir = build.cargo_out(&compiler, Mode::Librustc, target);
add_to_sysroot(&out_dir, &libdir);
PathBuf::from(out.trim())
}
+pub fn create_sysroot(build: &Build, compiler: &Compiler) {
+ // nothing to do in stage0
+ if compiler.stage == 0 {
+ return
+ }
+
+ let sysroot = build.sysroot(compiler);
+ let _ = fs::remove_dir_all(&sysroot);
+ t!(fs::create_dir_all(&sysroot));
+}
+
/// Prepare a new compiler from the artifacts in `stage`
///
/// This will assemble a compiler in `build/$host/stage$stage`. The compiler
if stage == 0 {
return
}
+
+ println!("Copying stage{} compiler ({})", stage, host);
+
// The compiler that we're assembling
let target_compiler = Compiler::new(stage, host);
// The compiler that compiled the compiler we're assembling
let build_compiler = Compiler::new(stage - 1, &build.config.build);
- // Clear out old files
- let sysroot = build.sysroot(&target_compiler);
- let _ = fs::remove_dir_all(&sysroot);
- t!(fs::create_dir_all(&sysroot));
-
// Link in all dylibs to the libdir
+ let sysroot = build.sysroot(&target_compiler);
let sysroot_libdir = sysroot.join(libdir(host));
t!(fs::create_dir_all(&sysroot_libdir));
let src_libdir = build.sysroot_libdir(&build_compiler, host);
pub docs: bool,
pub vendor: bool,
pub target_config: HashMap<String, Target>,
+ pub full_bootstrap: bool,
// llvm codegen options
pub llvm_assertions: bool,
vendor: Option<bool>,
nodejs: Option<String>,
python: Option<String>,
+ full_bootstrap: Option<bool>,
}
/// TOML representation of various global install decisions.
set(&mut config.docs, build.docs);
set(&mut config.submodules, build.submodules);
set(&mut config.vendor, build.vendor);
+ set(&mut config.full_bootstrap, build.full_bootstrap);
if let Some(ref install) = toml.install {
config.prefix = install.prefix.clone();
("NINJA", self.ninja),
("CODEGEN_TESTS", self.codegen_tests),
("VENDOR", self.vendor),
+ ("FULL_BOOTSTRAP", self.full_bootstrap),
}
match key {
# Indicate whether the vendored sources are used for Rust dependencies or not
#vendor = false
+# Typically the build system will build the rust compiler twice. The second
+# compiler, however, will simply use its own libraries to link against. If you
+# would rather to perform a full bootstrap, compiling the compiler three times,
+# then you can set this option to true. You shouldn't ever need to set this
+# option to true.
+#full-bootstrap = false
+
# =============================================================================
# General install configuration options
# =============================================================================
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
+ let compiler = if build.force_use_stage1(&compiler, target) {
+ Compiler::new(1, compiler.host)
+ } else {
+ compiler
+ };
let out_dir = build.stage_out(&compiler, Mode::Libstd)
.join(target).join("doc");
let rustdoc = build.rustdoc(&compiler);
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
+ let compiler = if build.force_use_stage1(&compiler, target) {
+ Compiler::new(1, compiler.host)
+ } else {
+ compiler
+ };
let out_dir = build.stage_out(&compiler, Mode::Libtest)
.join(target).join("doc");
let rustdoc = build.rustdoc(&compiler);
let out = build.doc_out(target);
t!(fs::create_dir_all(&out));
let compiler = Compiler::new(stage, &build.config.build);
+ let compiler = if build.force_use_stage1(&compiler, target) {
+ Compiler::new(1, compiler.host)
+ } else {
+ compiler
+ };
let out_dir = build.stage_out(&compiler, Mode::Librustc)
.join(target).join("doc");
let rustdoc = build.rustdoc(&compiler);
let mut cmd = Command::new(self.tool(&compiler, tool));
let host = compiler.host;
let mut paths = vec![
- self.cargo_out(compiler, Mode::Libstd, host).join("deps"),
- self.cargo_out(compiler, Mode::Libtest, host).join("deps"),
- self.cargo_out(compiler, Mode::Librustc, host).join("deps"),
+ self.sysroot_libdir(compiler, compiler.host),
self.cargo_out(compiler, Mode::Tool, host).join("deps"),
];
fn python(&self) -> &Path {
self.config.python.as_ref().unwrap()
}
+
+ /// Tests whether the `compiler` compiling for `target` should be forced to
+ /// use a stage1 compiler instead.
+ ///
+ /// Currently, by default, the build system does not perform a "full
+ /// bootstrap" by default where we compile the compiler three times.
+ /// Instead, we compile the compiler two times. The final stage (stage2)
+ /// just copies the libraries from the previous stage, which is what this
+ /// method detects.
+ ///
+ /// Here we return `true` if:
+ ///
+ /// * The build isn't performing a full bootstrap
+ /// * The `compiler` is in the final stage, 2
+ /// * We're not cross-compiling, so the artifacts are already available in
+ /// stage1
+ ///
+ /// When all of these conditions are met the build will lift artifacts from
+ /// the previous stage forward.
+ fn force_use_stage1(&self, compiler: &Compiler, target: &str) -> bool {
+ !self.config.full_bootstrap &&
+ compiler.stage >= 2 &&
+ self.config.host.iter().any(|h| h == target)
+ }
}
impl<'a> Compiler<'a> {
.profile(profile)
.define("LLVM_ENABLE_ASSERTIONS", assertions)
.define("LLVM_TARGETS_TO_BUILD",
- "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430")
+ "X86;ARM;AArch64;Mips;PowerPC;SystemZ;JSBackend;MSP430;Sparc;NVPTX")
.define("LLVM_INCLUDE_EXAMPLES", "OFF")
.define("LLVM_INCLUDE_TESTS", "OFF")
.define("LLVM_INCLUDE_DOCS", "OFF")
}
need_cmd("cmake".as_ref());
if build.config.ninja {
- need_cmd("ninja".as_ref())
+ // Some Linux distros rename `ninja` to `ninja-build`.
+ // CMake can work with either binary name.
+ if have_cmd("ninja-build".as_ref()).is_none() {
+ need_cmd("ninja".as_ref());
+ }
}
break
}
rules.run(&steps);
}
-pub fn build_rules(build: &Build) -> Rules {
+pub fn build_rules<'a>(build: &'a Build) -> Rules {
let mut rules = Rules::new(build);
// This is the first rule that we're going to define for rustbuild, which is
// the compiler with no target libraries ready to go
rules.build("rustc", "src/rustc")
+ .dep(|s| s.name("create-sysroot").target(s.host))
.dep(move |s| {
if s.stage == 0 {
Step::noop()
// Crate compilations
//
// Tools used during the build system but not shipped
+ rules.build("create-sysroot", "path/to/nowhere")
+ .run(move |s| compile::create_sysroot(build, &s.compiler()));
+
+ // These rules are "pseudo rules" that don't actually do any work
+ // themselves, but represent a complete sysroot with the relevant compiler
+ // linked into place.
+ //
+ // That is, depending on "libstd" means that when the rule is completed then
+ // the `stage` sysroot for the compiler `host` will be available with a
+ // standard library built for `target` linked in place. Not all rules need
+ // the compiler itself to be available, just the standard library, so
+ // there's a distinction between the two.
rules.build("libstd", "src/libstd")
- .dep(|s| s.name("build-crate-std_shim"));
+ .dep(|s| s.name("rustc").target(s.host))
+ .dep(|s| s.name("libstd-link"));
rules.build("libtest", "src/libtest")
- .dep(|s| s.name("build-crate-test_shim"));
+ .dep(|s| s.name("libstd"))
+ .dep(|s| s.name("libtest-link"))
+ .default(true);
rules.build("librustc", "src/librustc")
- .dep(|s| s.name("build-crate-rustc-main"));
+ .dep(|s| s.name("libtest"))
+ .dep(|s| s.name("librustc-link"))
+ .host(true)
+ .default(true);
+
+ // Helper method to define the rules to link a crate into its place in the
+ // sysroot.
+ //
+ // The logic here is a little subtle as there's a few cases to consider.
+ // Not all combinations of (stage, host, target) actually require something
+ // to be compiled, but rather libraries could get propagated from a
+ // different location. For example:
+ //
+ // * Any crate with a `host` that's not the build triple will not actually
+ // compile something. A different `host` means that the build triple will
+ // actually compile the libraries, and then we'll copy them over from the
+ // build triple to the `host` directory.
+ //
+ // * Some crates aren't even compiled by the build triple, but may be copied
+ // from previous stages. For example if we're not doing a full bootstrap
+ // then we may just depend on the stage1 versions of libraries to be
+ // available to get linked forward.
+ //
+ // * Finally, there are some cases, however, which do indeed comiple crates
+ // and link them into place afterwards.
+ //
+ // The rule definition below mirrors these three cases. The `dep` method
+ // calculates the correct dependency which either comes from stage1, a
+ // different compiler, or from actually building the crate itself (the `dep`
+ // rule). The `run` rule then mirrors these three cases and links the cases
+ // forward into the compiler sysroot specified from the correct location.
+ fn crate_rule<'a, 'b>(build: &'a Build,
+ rules: &'b mut Rules<'a>,
+ krate: &'a str,
+ dep: &'a str,
+ link: fn(&Build, &Compiler, &Compiler, &str))
+ -> RuleBuilder<'a, 'b> {
+ let mut rule = rules.build(&krate, "path/to/nowhere");
+ rule.dep(move |s| {
+ if build.force_use_stage1(&s.compiler(), s.target) {
+ s.host(&build.config.build).stage(1)
+ } else if s.host == build.config.build {
+ s.name(dep)
+ } else {
+ s.host(&build.config.build)
+ }
+ })
+ .run(move |s| {
+ if build.force_use_stage1(&s.compiler(), s.target) {
+ link(build,
+ &s.stage(1).host(&build.config.build).compiler(),
+ &s.compiler(),
+ s.target)
+ } else if s.host == build.config.build {
+ link(build, &s.compiler(), &s.compiler(), s.target)
+ } else {
+ link(build,
+ &s.host(&build.config.build).compiler(),
+ &s.compiler(),
+ s.target)
+ }
+ });
+ return rule
+ }
+
+ // Similar to the `libstd`, `libtest`, and `librustc` rules above, except
+ // these rules only represent the libraries being available in the sysroot,
+ // not the compiler itself. This is done as not all rules need a compiler in
+ // the sysroot, but may just need the libraries.
+ //
+ // All of these rules use the helper definition above.
+ crate_rule(build,
+ &mut rules,
+ "libstd-link",
+ "build-crate-std_shim",
+ compile::std_link)
+ .dep(|s| s.name("create-sysroot").target(s.host));
+ crate_rule(build,
+ &mut rules,
+ "libtest-link",
+ "build-crate-test_shim",
+ compile::test_link)
+ .dep(|s| s.name("libstd-link"));
+ crate_rule(build,
+ &mut rules,
+ "librustc-link",
+ "build-crate-rustc-main",
+ compile::rustc_link)
+ .dep(|s| s.name("libtest-link"));
+
for (krate, path, _default) in krates("std_shim") {
rules.build(&krate.build_step, path)
.dep(move |s| s.name("rustc").host(&build.config.build).target(s.host))
- .dep(move |s| {
- if s.host == build.config.build {
- Step::noop()
- } else {
- s.host(&build.config.build)
- }
- })
- .run(move |s| {
- if s.host == build.config.build {
- compile::std(build, s.target, &s.compiler())
- } else {
- compile::std_link(build, s.target, s.stage, s.host)
- }
- });
+ .run(move |s| compile::std(build, s.target, &s.compiler()));
}
- for (krate, path, default) in krates("test_shim") {
+ for (krate, path, _default) in krates("test_shim") {
rules.build(&krate.build_step, path)
- .dep(|s| s.name("libstd"))
- .dep(move |s| {
- if s.host == build.config.build {
- Step::noop()
- } else {
- s.host(&build.config.build)
- }
- })
- .default(default)
- .run(move |s| {
- if s.host == build.config.build {
- compile::test(build, s.target, &s.compiler())
- } else {
- compile::test_link(build, s.target, s.stage, s.host)
- }
- });
+ .dep(|s| s.name("libstd-link"))
+ .run(move |s| compile::test(build, s.target, &s.compiler()));
}
- for (krate, path, default) in krates("rustc-main") {
+ for (krate, path, _default) in krates("rustc-main") {
rules.build(&krate.build_step, path)
- .dep(|s| s.name("libtest"))
+ .dep(|s| s.name("libtest-link"))
.dep(move |s| s.name("llvm").host(&build.config.build).stage(0))
- .dep(move |s| {
- if s.host == build.config.build {
- Step::noop()
- } else {
- s.host(&build.config.build)
- }
- })
- .host(true)
- .default(default)
- .run(move |s| {
- if s.host == build.config.build {
- compile::rustc(build, s.target, &s.compiler())
- } else {
- compile::rustc_link(build, s.target, s.stage, s.host)
- }
- });
+ .run(move |s| compile::rustc(build, s.target, &s.compiler()));
}
// ========================================================================
.run(move |s| doc::standalone(build, s.stage, s.target));
rules.doc("doc-error-index", "src/tools/error_index_generator")
.dep(move |s| s.name("tool-error-index").target(&build.config.build))
- .dep(move |s| s.name("librustc"))
+ .dep(move |s| s.name("librustc-link"))
.default(build.config.docs)
.host(true)
.run(move |s| doc::error_index(build, s.stage, s.target));
for (krate, path, default) in krates("std_shim") {
rules.doc(&krate.doc_step, path)
- .dep(|s| s.name("libstd"))
+ .dep(|s| s.name("libstd-link"))
.default(default && build.config.docs)
.run(move |s| doc::std(build, s.stage, s.target));
}
for (krate, path, default) in krates("test_shim") {
rules.doc(&krate.doc_step, path)
- .dep(|s| s.name("libtest"))
+ .dep(|s| s.name("libtest-link"))
.default(default && build.config.compiler_docs)
.run(move |s| doc::test(build, s.stage, s.target));
}
for (krate, path, default) in krates("rustc-main") {
rules.doc(&krate.doc_step, path)
- .dep(|s| s.name("librustc"))
+ .dep(|s| s.name("librustc-link"))
.host(true)
.default(default && build.config.compiler_docs)
.run(move |s| doc::rustc(build, s.stage, s.target));
// for the `rust-std` package, so if this is a host target we
// depend on librustc and otherwise we just depend on libtest.
if build.config.host.iter().any(|t| t == s.target) {
- s.name("librustc")
+ s.name("librustc-link")
} else {
- s.name("libtest")
+ s.name("libtest-link")
}
})
.default(true)
} else {
&self.build.config.target
};
- // If --target was specified but --host wasn't specified, don't run
- // any host-only tests
+ // Determine the actual targets participating in this rule.
+ // NOTE: We should keep the full projection from build triple to
+ // the hosts for the dist steps, now that the hosts array above is
+ // truncated to avoid duplication of work in that case. Therefore
+ // the original non-shadowed hosts array is used below.
let arr = if rule.host {
- if self.build.flags.target.len() > 0 &&
- self.build.flags.host.len() == 0 {
- &hosts[..0]
+ // If --target was specified but --host wasn't specified,
+ // don't run any host-only tests. Also, respect any `--host`
+ // overrides as done for `hosts`.
+ if self.build.flags.host.len() > 0 {
+ &self.build.flags.host[..]
+ } else if self.build.flags.target.len() > 0 {
+ &[]
} else {
- hosts
+ &self.build.config.host[..]
}
} else {
targets
python2.7 \
git \
cmake \
- ccache \
unzip \
expect \
openjdk-9-jre \
--i686-linux-android-ndk=/android/ndk-x86-9 \
--aarch64-linux-android-ndk=/android/ndk-aarch64
ENV XPY_CHECK test --target arm-linux-androideabi
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
set -ex
ANDROID_EMULATOR_FORCE_32BIT=true \
- emulator @arm-18 -no-window -partition-size 2047 &
+ nohup nohup emulator @arm-18 -no-window -partition-size 2047 \
+ 0<&- &>/dev/null &
+adb wait-for-device
exec "$@"
python2.7 \
git \
cmake \
- ccache \
sudo \
gcc-aarch64-linux-gnu libc6-dev-arm64-cross \
gcc-arm-linux-gnueabi libc6-dev-armel-cross \
# FIXME(rust-lang/rust#36150): powerpc unfortunately aborts right now
ENV NO_LLVM_ASSERTIONS=1
-
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
python2.7 \
git \
cmake \
- ccache \
sudo \
gdb \
xz-utils
ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests
ENV RUST_CHECK_TARGET check
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
python2.7 \
git \
cmake \
- ccache \
sudo \
gdb \
xz-utils
ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu
ENV RUST_CHECK_TARGET check
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
python2.7 \
git \
cmake \
- ccache \
sudo \
bzip2 \
xz-utils \
ENV RUST_CONFIGURE_ARGS --target=x86_64-unknown-freebsd
ENV RUST_CHECK_TARGET ""
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
python2.7 \
git \
cmake \
- ccache \
libssl-dev \
sudo \
xz-utils \
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
ENV RUST_CHECK_TARGET check-cargotest
ENV NO_VENDOR 1
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
python2.7 \
git \
cmake \
- ccache \
sudo \
gdb \
xz-utils
--enable-debug \
--enable-optimize
ENV RUST_CHECK_TARGET ""
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
--- /dev/null
+FROM ubuntu:16.04
+
+RUN apt-get update && apt-get install -y --no-install-recommends \
+ g++ \
+ make \
+ file \
+ curl \
+ ca-certificates \
+ python2.7 \
+ git \
+ cmake \
+ sudo \
+ gdb \
+ 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 -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 RUST_CONFIGURE_ARGS \
+ --build=x86_64-unknown-linux-gnu \
+ --enable-full-bootstrap
+ENV RUST_CHECK_TARGET ""
python2.7 \
git \
cmake \
- ccache \
sudo \
gdb \
llvm-3.7-tools \
--build=x86_64-unknown-linux-gnu \
--llvm-root=/usr/lib/llvm-3.7
ENV RUST_CHECK_TARGET check
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
python2.7 \
git \
cmake \
- ccache \
sudo \
gdb \
xz-utils
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --disable-rustbuild
ENV RUST_CHECK_TARGET check
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
python2.7 \
git \
cmake \
- ccache \
sudo \
gdb \
xz-utils
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --disable-optimize-tests
ENV RUST_CHECK_TARGET check
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
python2.7 \
git \
cmake \
- ccache \
sudo \
gdb \
xz-utils
ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu
ENV RUST_CHECK_TARGET check
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
python2.7 \
git \
cmake \
- ccache \
xz-utils \
sudo \
gdb
ENV RUST_CHECK_TARGET check-stage2-T-x86_64-unknown-linux-musl-H-x86_64-unknown-linux-gnu
ENV PATH=$PATH:/musl-x86_64/bin
ENV XPY_CHECK test --target x86_64-unknown-linux-musl
-
-RUN mkdir /tmp/obj
-RUN chmod 777 /tmp/obj
The most common case of coercion is removing mutability from a reference:
- * `&mut T` to `&T`
+* `&mut T` to `&T`
An analogous conversion is to remove mutability from a
[raw pointer](raw-pointers.md):
- * `*mut T` to `*const T`
+* `*mut T` to `*const T`
References can also be coerced to raw pointers:
- * `&T` to `*const T`
+* `&T` to `*const T`
- * `&mut T` to `*mut T`
+* `&mut T` to `*mut T`
Custom coercions may be defined using [`Deref`](deref-coercions.md).
A cast `e as U` is also valid in any of the following cases:
- * `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
- * `e` is a C-like enum (with no data attached to the variants),
- and `U` is an integer type; *enum-cast*
- * `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast*
- * `e` has type `u8` and `U` is `char`; *u8-char-cast*
+* `e` has type `T` and `T` and `U` are any numeric types; *numeric-cast*
+* `e` is a C-like enum (with no data attached to the variants),
+ and `U` is an integer type; *enum-cast*
+* `e` has type `bool` or `char` and `U` is an integer type; *prim-int-cast*
+* `e` has type `u8` and `U` is `char`; *u8-char-cast*
For example
```
The `no_run` attribute will compile your code, but not run it. This is
-important for examples such as "Here's how to start up a network service,"
-which you would want to make sure compile, but might run in an infinite loop!
+important for examples such as "Here's how to retrieve a web page,"
+which you would want to ensure compiles, but might be run in a test
+environment that has no network access.
### Documenting modules
definitions for the C standard library in the `libc` module, and Rust links
against `libc` and `libm` by default.
+# Variadic functions
+
+In C, functions can be 'variadic', meaning they accept a variable number of arguments. This can
+be achieved in Rust by specifying `...` within the argument list of a foreign function declaration:
+
+```no_run
+extern {
+ fn foo(x: i32, ...);
+}
+
+fn main() {
+ unsafe {
+ foo(10, 20, 30, 40, 50);
+ }
+}
+```
+
+Normal Rust functions can *not* be variadic:
+
+```ignore
+// This will not compile
+
+fn foo(x: i32, ...) { }
+```
+
# The "nullable pointer optimization"
Certain Rust types are defined to never be `null`. This includes references (`&T`,
# Testing and concurrency
-One thing that is important to note when writing tests is that they may be run
-concurrently using threads. For this reason you should take care that your tests
-are written in such a way as to not depend on each-other, or on any shared
-state. "Shared state" can also include the environment, such as the current
-working directory, or environment variables.
+It is important to note that tests are run concurrently using threads. For this
+reason, care should be taken to ensure your tests do not depend on each-other,
+or on any shared state. "Shared state" can also include the environment, such
+as the current working directory, or environment variables.
If this is an issue it is possible to control this concurrency, either by
setting the environment variable `RUST_TEST_THREADS`, or by passing the argument
There are other good reasons to avoid mutable state when possible, but they’re
out of the scope of this guide. In general, you can often avoid explicit
mutation, and so it is preferable in Rust. That said, sometimes, mutation is
-what you need, so it’s not verboten.
+what you need, so it’s not forbidden.
# Initializing bindings
functions defined in Rust. The Rust compiler automatically translates between
the Rust ABI and the foreign ABI.
+Functions within external blocks may be variadic by specifying `...` after one
+or more named arguments in the argument list:
+
+```ignore
+extern {
+ fn foo(x: i32, ...);
+}
+```
+
A number of [attributes](#ffi-attributes) control the behavior of external blocks.
By default external blocks assume that the library they are calling uses the
--- /dev/null
+{
+ "intrinsic_prefix": "_",
+ "llvm_prefix": "llvm.cuda.",
+ "intrinsics": [
+ {
+ "intrinsic": "syncthreads",
+ "width": ["0"],
+ "llvm": "syncthreads",
+ "ret": "V",
+ "args": []
+ }
+ ]
+}
--- /dev/null
+{
+ "platform": "nvptx",
+ "number_info": {
+ "signed": {}
+ },
+ "width_info": {}
+}
--- /dev/null
+{
+ "intrinsic_prefix": "_",
+ "llvm_prefix": "llvm.nvvm.read.ptx.sreg.",
+ "intrinsics": [
+ {
+ "intrinsic": "block_dim_x",
+ "width": ["0"],
+ "llvm": "ntid.x",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "block_dim_y",
+ "width": ["0"],
+ "llvm": "ntid.y",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "block_dim_z",
+ "width": ["0"],
+ "llvm": "ntid.z",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "block_idx_x",
+ "width": ["0"],
+ "llvm": "ctaid.x",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "block_idx_y",
+ "width": ["0"],
+ "llvm": "ctaid.y",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "block_idx_z",
+ "width": ["0"],
+ "llvm": "ctaid.z",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "grid_dim_x",
+ "width": ["0"],
+ "llvm": "nctaid.x",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "grid_dim_y",
+ "width": ["0"],
+ "llvm": "nctaid.y",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "grid_dim_z",
+ "width": ["0"],
+ "llvm": "nctaid.z",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "thread_idx_x",
+ "width": ["0"],
+ "llvm": "tid.x",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "thread_idx_y",
+ "width": ["0"],
+ "llvm": "tid.y",
+ "ret": "S32",
+ "args": []
+ },
+ {
+ "intrinsic": "thread_idx_z",
+ "width": ["0"],
+ "llvm": "tid.z",
+ "ret": "S32",
+ "args": []
+ }
+ ]
+}
/// [`RwLock`][rwlock], or one of the [`Atomic`][atomic] types.
///
/// `Arc` uses atomic operations for reference counting, so `Arc`s can be
-/// sent between threads. In other words, `Arc<T>` implements [`Send`][send]
-/// as long as `T` implements `Send` and [`Sync`][sync]. The disadvantage is
+/// sent between threads. In other words, `Arc<T>` implements [`Send`]
+/// as long as `T` implements [`Send`] and [`Sync`][sync]. The disadvantage is
/// that atomic operations are more expensive than ordinary memory accesses.
/// If you are not sharing reference-counted values between threads, consider
-/// using [`rc::Rc`][rc] for lower overhead. `Rc` is a safe default, because
-/// the compiler will catch any attempt to send an `Rc` between threads.
+/// using [`rc::Rc`] for lower overhead. [`Rc`] is a safe default, because
+/// the compiler will catch any attempt to send an [`Rc`] between threads.
/// However, a library might choose `Arc` in order to give library consumers
/// more flexibility.
///
/// The [`downgrade`][downgrade] method can be used to create a non-owning
-/// [`Weak`][weak] pointer. A `Weak` pointer can be [`upgrade`][upgrade]d
-/// to an `Arc`, but this will return [`None`][option] if the value has
-/// already been dropped.
+/// [`Weak`][weak] pointer. A [`Weak`][weak] pointer can be [`upgrade`][upgrade]d
+/// to an `Arc`, but this will return [`None`] if the value has already been
+/// dropped.
///
/// A cycle between `Arc` pointers will never be deallocated. For this reason,
-/// `Weak` is used to break cycles. For example, a tree could have strong
-/// `Arc` pointers from parent nodes to children, and `Weak` pointers from
-/// children back to their parents.
+/// [`Weak`][weak] is used to break cycles. For example, a tree could have
+/// strong `Arc` pointers from parent nodes to children, and [`Weak`][weak]
+/// pointers from children back to their parents.
///
/// `Arc<T>` automatically dereferences to `T` (via the [`Deref`][deref] trait),
/// so you can call `T`'s methods on a value of type `Arc<T>`. To avoid name
/// Arc::downgrade(&my_arc);
/// ```
///
-/// `Weak<T>` does not auto-dereference to `T`, because the value may have
+/// [`Weak<T>`][weak] does not auto-dereference to `T`, because the value may have
/// already been destroyed.
///
/// [arc]: struct.Arc.html
/// [weak]: struct.Weak.html
-/// [rc]: ../../std/rc/struct.Rc.html
+/// [`Rc`]: ../../std/rc/struct.Rc.html
/// [clone]: ../../std/clone/trait.Clone.html#tymethod.clone
/// [mutex]: ../../std/sync/struct.Mutex.html
/// [rwlock]: ../../std/sync/struct.RwLock.html
/// [atomic]: ../../std/sync/atomic/index.html
-/// [send]: ../../std/marker/trait.Send.html
+/// [`Send`]: ../../std/marker/trait.Send.html
/// [sync]: ../../std/marker/trait.Sync.html
/// [deref]: ../../std/ops/trait.Deref.html
/// [downgrade]: struct.Arc.html#method.downgrade
/// [upgrade]: struct.Weak.html#method.upgrade
-/// [option]: ../../std/option/enum.Option.html
+/// [`None`]: ../../std/option/enum.Option.html#variant.None
/// [assoc]: ../../book/method-syntax.html#associated-functions
///
/// # Examples
/// }
/// ```
///
-/// Sharing a mutable `AtomicUsize`:
+/// Sharing a mutable [`AtomicUsize`]:
+///
+/// [`AtomicUsize`]: ../../std/sync/atomic/struct.AtomicUsize.html
///
/// ```no_run
/// use std::sync::Arc;
}
#[cfg(not(test))]
+#[cfg(stage0)]
#[lang = "exchange_free"]
#[inline]
unsafe fn exchange_free(ptr: *mut u8, old_size: usize, align: usize) {
// targets, which means we have to build the alloc_jemalloc crate
// for targets like emscripten, even if we don't use it.
if target.contains("rumprun") || target.contains("bitrig") || target.contains("openbsd") ||
- target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") {
+ target.contains("msvc") || target.contains("emscripten") || target.contains("fuchsia") ||
+ target.contains("redox") {
println!("cargo:rustc-cfg=dummy_jemalloc");
return;
}
issue = "27783")]
#![feature(allocator)]
#![feature(staged_api)]
-#![cfg_attr(unix, feature(libc))]
+#![cfg_attr(any(unix, target_os = "redox"), feature(libc))]
// The minimum alignment guaranteed by the architecture. This value is used to
// add fast paths for low alignment values. In practice, the alignment is a
imp::usable_size(size, align)
}
-#[cfg(unix)]
+#[cfg(any(unix, target_os = "redox"))]
mod imp {
extern crate libc;
}
}
- #[cfg(target_os = "android")]
+ #[cfg(any(target_os = "android", target_os = "redox"))]
unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
// On android we currently target API level 9 which unfortunately
// doesn't have the `posix_memalign` API used below. Instead we use
libc::memalign(align as libc::size_t, size as libc::size_t) as *mut u8
}
- #[cfg(not(target_os = "android"))]
+ #[cfg(not(any(target_os = "android", target_os = "redox")))]
unsafe fn aligned_malloc(size: usize, align: usize) -> *mut u8 {
let mut out = ptr::null_mut();
let ret = libc::posix_memalign(&mut out, align as libc::size_t, size as libc::size_t);
name = "collectionstest"
path = "../libcollectionstest/lib.rs"
-[[bench]]
-name = "collectionstest"
-path = "../libcollectionstest/lib.rs"
+# FIXME: need to extract benchmarks to separate crate
+#[[bench]]
+#name = "collectionstest"
+#path = "../libcollectionstest/lib.rs"
/// [`peek_mut()`]: struct.BinaryHeap.html#method.peek_mut
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
pub struct PeekMut<'a, T: 'a + Ord> {
- heap: &'a mut BinaryHeap<T>
+ heap: &'a mut BinaryHeap<T>,
}
#[stable(feature = "binary_heap_peek_mut", since = "1.12.0")]
if self.is_empty() {
None
} else {
- Some(PeekMut {
- heap: self
- })
+ Some(PeekMut { heap: self })
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, T> IntoIterator for &'a BinaryHeap<T> where T: Ord {
+impl<'a, T> IntoIterator for &'a BinaryHeap<T>
+ where T: Ord
+{
type Item = &'a T;
type IntoIter = Iter<'a, T>;
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> ToOwned for T where T: Clone {
+impl<T> ToOwned for T
+ where T: Clone
+{
type Owned = T;
fn to_owned(&self) -> T {
self.clone()
{
/// Borrowed data.
#[stable(feature = "rust1", since = "1.0.0")]
- Borrowed(#[stable(feature = "rust1", since = "1.0.0")] &'a B),
+ Borrowed(#[stable(feature = "rust1", since = "1.0.0")]
+ &'a B),
/// Owned data.
#[stable(feature = "rust1", since = "1.0.0")]
- Owned(
- #[stable(feature = "rust1", since = "1.0.0")] <B as ToOwned>::Owned
- ),
+ Owned(#[stable(feature = "rust1", since = "1.0.0")]
+ <B as ToOwned>::Owned),
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> Clone for Cow<'a, B> where B: ToOwned {
+impl<'a, B: ?Sized> Clone for Cow<'a, B>
+ where B: ToOwned
+{
fn clone(&self) -> Cow<'a, B> {
match *self {
Borrowed(b) => Borrowed(b),
}
}
-impl<'a, B: ?Sized> Cow<'a, B> where B: ToOwned {
+impl<'a, B: ?Sized> Cow<'a, B>
+ where B: ToOwned
+{
/// Acquires a mutable reference to the owned form of the data.
///
/// Clones the data if it is not already owned.
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> Deref for Cow<'a, B> where B: ToOwned {
+impl<'a, B: ?Sized> Deref for Cow<'a, B>
+ where B: ToOwned
+{
type Target = B;
fn deref(&self) -> &B {
impl<'a, B: ?Sized> Eq for Cow<'a, B> where B: Eq + ToOwned {}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> Ord for Cow<'a, B> where B: Ord + ToOwned {
+impl<'a, B: ?Sized> Ord for Cow<'a, B>
+ where B: Ord + ToOwned
+{
#[inline]
fn cmp(&self, other: &Cow<'a, B>) -> Ordering {
Ord::cmp(&**self, &**other)
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> PartialOrd for Cow<'a, B> where B: PartialOrd + ToOwned {
+impl<'a, B: ?Sized> PartialOrd for Cow<'a, B>
+ where B: PartialOrd + ToOwned
+{
#[inline]
fn partial_cmp(&self, other: &Cow<'a, B>) -> Option<Ordering> {
PartialOrd::partial_cmp(&**self, &**other)
}
#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, B: ?Sized> Hash for Cow<'a, B> where B: Hash + ToOwned {
+impl<'a, B: ?Sized> Hash for Cow<'a, B>
+ where B: Hash + ToOwned
+{
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
Hash::hash(&**self, state)
}
}
-impl<'a, E> IntoIterator for &'a EnumSet<E> where E: CLike
+impl<'a, E> IntoIterator for &'a EnumSet<E>
+ where E: CLike
{
type Item = E;
type IntoIter = Iter<E>;
//! A doubly-linked list with owned nodes.
//!
-//! The `LinkedList` allows pushing and popping elements at either end and is thus
-//! efficiently usable as a double-ended queue.
+//! The `LinkedList` allows pushing and popping elements at either end
+//! in constant time.
+//!
+//! Almost always it is better to use `Vec` or [`VecDeque`] instead of
+//! [`LinkedList`]. In general, array-based containers are faster,
+//! more memory efficient and make better use of CPU cache.
+//!
+//! [`LinkedList`]: ../linked_list/struct.LinkedList.html
+//! [`VecDeque`]: ../vec_deque/struct.VecDeque.html
#![stable(feature = "rust1", since = "1.0.0")]
use super::SpecExtend;
-/// A doubly-linked list.
+/// A doubly-linked list with owned nodes.
+///
+/// The `LinkedList` allows pushing and popping elements at either end
+/// in constant time.
+///
+/// Almost always it is better to use `Vec` or `VecDeque` instead of
+/// `LinkedList`. In general, array-based containers are faster,
+/// more memory efficient and make better use of CPU cache.
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LinkedList<T> {
head: Option<Shared<Node<T>>>,
pub fn append(&mut self, other: &mut Self) {
match self.tail {
None => mem::swap(self, other),
- Some(tail) => if let Some(other_head) = other.head.take() {
- unsafe {
- (**tail).next = Some(other_head);
- (**other_head).prev = Some(tail);
- }
+ Some(tail) => {
+ if let Some(other_head) = other.head.take() {
+ unsafe {
+ (**tail).next = Some(other_head);
+ (**other_head).prev = Some(tail);
+ }
- self.tail = other.tail.take();
- self.len += mem::replace(&mut other.len, 0);
- },
+ self.tail = other.tail.take();
+ self.len += mem::replace(&mut other.len, 0);
+ }
+ }
}
}
reason = "method name and placement protocol are subject to change",
issue = "30172")]
pub fn front_place(&mut self) -> FrontPlace<T> {
- FrontPlace { list: self, node: IntermediateBox::make_place() }
+ FrontPlace {
+ list: self,
+ node: IntermediateBox::make_place(),
+ }
}
/// Returns a place for insertion at the back of the list.
reason = "method name and placement protocol are subject to change",
issue = "30172")]
pub fn back_place(&mut self) -> BackPlace<T> {
- BackPlace { list: self, node: IntermediateBox::make_place() }
+ BackPlace {
+ list: self,
+ node: IntermediateBox::make_place(),
+ }
}
}
(**head).prev = node;
self.list.len += 1;
- }
+ },
}
}
// Ensure that `LinkedList` and its read-only iterators are covariant in their type parameters.
#[allow(dead_code)]
fn assert_covariance() {
- fn a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> { x }
- fn b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> { x }
- fn c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> { x }
+ fn a<'a>(x: LinkedList<&'static str>) -> LinkedList<&'a str> {
+ x
+ }
+ fn b<'i, 'a>(x: Iter<'i, &'static str>) -> Iter<'i, &'a str> {
+ x
+ }
+ fn c<'a>(x: IntoIter<&'static str>) -> IntoIter<&'a str> {
+ x
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
fn test_send() {
let n = list_from(&[1, 2, 3]);
thread::spawn(move || {
- check_links(&n);
- let a: &[_] = &[&1, &2, &3];
- assert_eq!(a, &n.iter().collect::<Vec<_>>()[..]);
- })
+ check_links(&n);
+ let a: &[_] = &[&1, &2, &3];
+ assert_eq!(a, &n.iter().collect::<Vec<_>>()[..]);
+ })
.join()
.ok()
.unwrap();
debug_assert!('Σ'.len_utf8() == 2);
let is_word_final = case_ignoreable_then_cased(from[..i].chars().rev()) &&
!case_ignoreable_then_cased(from[i + 2..].chars());
- to.push_str(if is_word_final {
- "ς"
- } else {
- "σ"
- });
+ to.push_str(if is_word_final { "ς" } else { "σ" });
}
fn case_ignoreable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool {
unsafe { *xs.get_unchecked(i) }
}
fn safe_get(xs: &[u8], i: usize, total: usize) -> u8 {
- if i >= total {
- 0
- } else {
- unsafe_get(xs, i)
- }
+ if i >= total { 0 } else { unsafe_get(xs, i) }
}
let mut res = String::with_capacity(total);
pub fn push(&mut self, ch: char) {
match ch.len_utf8() {
1 => self.vec.push(ch as u8),
- _ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0;4]).as_bytes()),
+ _ => self.vec.extend_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()),
}
}
#[stable(feature = "from_string_for_vec_u8", since = "1.14.0")]
impl From<String> for Vec<u8> {
- fn from(string : String) -> Vec<u8> {
+ fn from(string: String) -> Vec<u8> {
string.into_bytes()
}
}
unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) {
#[allow(dead_code)]
fn diff(a: usize, b: usize) -> usize {
- if a <= b {
- b - a
- } else {
- a - b
- }
+ if a <= b { b - a } else { a - b }
}
debug_assert!(cmp::min(diff(dst, src), self.cap() - diff(dst, src)) + len <= self.cap(),
"wrc dst={} src={} len={} cap={}",
let old_cap = self.cap();
let used_cap = self.len() + 1;
let new_cap = used_cap.checked_add(additional)
- .and_then(|needed_cap| needed_cap.checked_next_power_of_two())
- .expect("capacity overflow");
+ .and_then(|needed_cap| needed_cap.checked_next_power_of_two())
+ .expect("capacity overflow");
if new_cap > self.capacity() {
self.buf.reserve_exact(used_cap, new_cap - used_cap);
let contiguous = self.is_contiguous();
- match (contiguous,
- distance_to_tail <= distance_to_head,
- idx >= self.tail) {
+ match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) {
(true, true, _) if index == 0 => {
// push_front
//
let contiguous = self.is_contiguous();
- match (contiguous,
- distance_to_tail <= distance_to_head,
- idx >= self.tail) {
+ match (contiguous, distance_to_tail <= distance_to_head, idx >= self.tail) {
(true, true, _) => {
unsafe {
// contiguous, remove closer to tail:
}
/// Returns the two slices that cover the VecDeque's valid range
-trait RingSlices : Sized {
+trait RingSlices: Sized {
fn slice(self, from: usize, to: usize) -> Self;
fn split_at(self, i: usize) -> (Self, Self);
}
fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
- where F: FnMut(Acc, Self::Item) -> Acc,
+ where F: FnMut(Acc, Self::Item) -> Acc
{
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
accum = front.iter().fold(accum, &mut f);
}
fn fold<Acc, F>(self, mut accum: Acc, mut f: F) -> Acc
- where F: FnMut(Acc, Self::Item) -> Acc,
+ where F: FnMut(Acc, Self::Item) -> Acc
{
let (front, back) = RingSlices::ring_slices(self.ring, self.head, self.tail);
accum = front.iter_mut().fold(accum, &mut f);
(_, 0) => {
source_deque.head = drain_tail;
}
- _ => {
- unsafe {
- if tail_len <= head_len {
- source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
- source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
- } else {
- source_deque.head = source_deque.wrap_add(drain_tail, head_len);
- source_deque.wrap_copy(drain_tail, drain_head, head_len);
- }
+ _ => unsafe {
+ if tail_len <= head_len {
+ source_deque.tail = source_deque.wrap_sub(drain_head, tail_len);
+ source_deque.wrap_copy(source_deque.tail, orig_tail, tail_len);
+ } else {
+ source_deque.head = source_deque.wrap_add(drain_tail, head_len);
+ source_deque.wrap_copy(drain_tail, drain_head, head_len);
}
- }
+ },
}
}
}
// We need to extend the buf if it's not a power of two, too small
// or doesn't have at least one free space
- if !buf.cap().is_power_of_two()
- || (buf.cap() < (MINIMUM_CAPACITY + 1))
- || (buf.cap() == len)
- {
+ if !buf.cap().is_power_of_two() || (buf.cap() < (MINIMUM_CAPACITY + 1)) ||
+ (buf.cap() == len) {
let cap = cmp::max(buf.cap() + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
buf.reserve_exact(len, cap - len);
}
VecDeque {
tail: 0,
head: len,
- buf: buf
+ buf: buf,
}
}
}
// do this in at most three copy moves.
if (cap - tail) > head {
// right hand block is the long one; move that enough for the left
- ptr::copy(
- buf.offset(tail as isize),
- buf.offset((tail - head) as isize),
- cap - tail);
+ ptr::copy(buf.offset(tail as isize),
+ buf.offset((tail - head) as isize),
+ cap - tail);
// copy left in the end
ptr::copy(buf, buf.offset((cap - head) as isize), head);
// shift the new thing to the start
- ptr::copy(buf.offset((tail-head) as isize), buf, len);
+ ptr::copy(buf.offset((tail - head) as isize), buf, len);
} else {
// left hand block is the long one, we can do it in two!
- ptr::copy(buf, buf.offset((cap-tail) as isize), head);
- ptr::copy(buf.offset(tail as isize), buf, cap-tail);
+ ptr::copy(buf, buf.offset((cap - tail) as isize), head);
+ ptr::copy(buf.offset(tail as isize), buf, cap - tail);
}
} else {
// Need to use N swaps to move the ring
// We should see the correct values in the VecDeque
let expected: VecDeque<_> = (0..drain_start)
- .chain(drain_end..len)
- .collect();
+ .chain(drain_end..len)
+ .collect();
assert_eq!(expected, tester);
}
}
let cap = (2i32.pow(cap_pwr) - 1) as usize;
// In these cases there is enough free space to solve it with copies
- for len in 0..((cap+1)/2) {
+ for len in 0..((cap + 1) / 2) {
// Test contiguous cases
- for offset in 0..(cap-len) {
+ for offset in 0..(cap - len) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at end of buffer is bigger than block at start
- for offset in (cap-len)..(cap-(len/2)) {
+ for offset in (cap - len)..(cap - (len / 2)) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at start of buffer is bigger than block at end
- for offset in (cap-(len/2))..cap {
+ for offset in (cap - (len / 2))..cap {
create_vec_and_test_convert(cap, offset, len)
}
}
// the ring will use swapping when:
// (cap + 1 - offset) > (cap + 1 - len) && (len - (cap + 1 - offset)) > (cap + 1 - len))
// right block size > free space && left block size > free space
- for len in ((cap+1)/2)..cap {
+ for len in ((cap + 1) / 2)..cap {
// Test contiguous cases
- for offset in 0..(cap-len) {
+ for offset in 0..(cap - len) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at end of buffer is bigger than block at start
- for offset in (cap-len)..(cap-(len/2)) {
+ for offset in (cap - len)..(cap - (len / 2)) {
create_vec_and_test_convert(cap, offset, len)
}
// Test cases where block at start of buffer is bigger than block at end
- for offset in (cap-(len/2))..cap {
+ for offset in (cap - (len / 2))..cap {
create_vec_and_test_convert(cap, offset, len)
}
}
"atomic_thread_fence.c"]);
}
- if !target.contains("windows") {
+ if !target.contains("redox") && !target.contains("windows") {
sources.extend(&["emutls.c"]);
}
name = "coretest"
path = "../libcoretest/lib.rs"
-[[bench]]
-name = "coretest"
-path = "../libcoretest/lib.rs"
+# FIXME: need to extract benchmarks to a separate crate
+#[[bench]]
+#name = "coretest"
+#path = "../libcoretest/lib.rs"
/// Loads a value from the bool.
///
- /// `load` takes an `Ordering` argument which describes the memory ordering of this operation.
+ /// `load` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation.
///
/// # Panics
///
- /// Panics if `order` is `Release` or `AcqRel`.
+ /// Panics if `order` is [`Release`] or [`AcqRel`].
+ ///
+ /// [`Ordering`]: enum.Ordering.html
+ /// [`Release`]: enum.Ordering.html#variant.Release
+ /// [`AcqRel`]: enum.Ordering.html#variant.Release
///
/// # Examples
///
/// Stores a value into the bool.
///
- /// `store` takes an `Ordering` argument which describes the memory ordering of this operation.
+ /// `store` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation.
+ ///
+ /// [`Ordering`]: enum.Ordering.html
///
/// # Examples
///
/// Stores a value into the bool, returning the old value.
///
- /// `swap` takes an `Ordering` argument which describes the memory ordering of this operation.
+ /// `swap` takes an [`Ordering`] argument which describes the memory ordering
+ /// of this operation.
+ ///
+ /// [`Ordering`]: enum.Ordering.html
///
/// # Examples
///
/// The return value is always the previous value. If it is equal to `current`, then the value
/// was updated.
///
- /// `compare_and_swap` also takes an `Ordering` argument which describes the memory ordering of
- /// this operation.
+ /// `compare_and_swap` also takes an [`Ordering`] argument which describes the memory
+ /// ordering of this operation.
+ ///
+ /// [`Ordering`]: enum.Ordering.html
///
/// # Examples
///
/// The return value is a result indicating whether the new value was written and containing
/// the previous value. On success this value is guaranteed to be equal to `current`.
///
- /// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this
- /// operation. The first describes the required ordering if the operation succeeds while the
- /// second describes the required ordering when the operation fails. The failure ordering can't
- /// be `Release` or `AcqRel` and must be equivalent or weaker than the success ordering.
+ /// `compare_exchange` takes two [`Ordering`] arguments to describe the memory
+ /// ordering of this operation. The first describes the required ordering if the
+ /// operation succeeds while the second describes the required ordering when the
+ /// operation fails. The failure ordering can't be [`Release`] or [`AcqRel`] and must
+ /// be equivalent or weaker than the success ordering.
+ ///
+ /// [`Ordering`]: enum.Ordering.html
+ /// [`Release`]: enum.Ordering.html#variant.Release
+ /// [`AcqRel`]: enum.Ordering.html#variant.Release
///
/// # Examples
///
/// return value is a result indicating whether the new value was written and containing the
/// previous value.
///
- /// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory
+ /// `compare_exchange_weak` takes two [`Ordering`] arguments to describe the memory
/// ordering of this operation. The first describes the required ordering if the operation
/// succeeds while the second describes the required ordering when the operation fails. The
- /// failure ordering can't be `Release` or `AcqRel` and must be equivalent or weaker than the
- /// success ordering.
+ /// failure ordering can't be [`Release`] or [`AcqRel`] and must be equivalent or
+ /// weaker than the success ordering.
+ ///
+ /// [`Ordering`]: enum.Ordering.html
+ /// [`Release`]: enum.Ordering.html#variant.Release
+ /// [`AcqRel`]: enum.Ordering.html#variant.Release
///
/// # Examples
///
-Subproject commit 0ac39c5ccf6a04395b7c40dd62321cb91f63f160
+Subproject commit e49e9bb7c3d9c7f2fd893f0ee0db81617b8db21f
authors = ["The Rust Project Developers"]
name = "proc_macro_tokens"
version = "0.0.0"
+build = false
[lib]
path = "lib.rs"
self.opt_expr(base, field_cfg)
}
- hir::ExprRepeat(ref elem, ref count) => {
- self.straightline(expr, pred, [elem, count].iter().map(|&e| &**e))
- }
-
hir::ExprAssign(ref l, ref r) |
hir::ExprAssignOp(_, ref l, ref r) => {
self.straightline(expr, pred, [r, l].iter().map(|&e| &**e))
hir::ExprType(ref e, _) |
hir::ExprUnary(_, ref e) |
hir::ExprField(ref e, _) |
- hir::ExprTupField(ref e, _) => {
+ hir::ExprTupField(ref e, _) |
+ hir::ExprRepeat(ref e, _) => {
self.straightline(expr, pred, Some(&**e).into_iter())
}
}
}
+ /// True if we are actually building the full dep-graph.
+ #[inline]
+ pub fn is_fully_enabled(&self) -> bool {
+ self.data.thread.is_fully_enabled()
+ }
+
pub fn query(&self) -> DepGraphQuery<DefId> {
self.data.thread.query()
}
debug!("Ended task {:?}", task_id);
}
+ fn visit_trait_item(&mut self, i: &'tcx hir::TraitItem) {
+ let trait_item_def_id = self.tcx.map.local_def_id(i.id);
+ let task_id = (self.dep_node_fn)(trait_item_def_id);
+ let _task = self.tcx.dep_graph.in_task(task_id.clone());
+ debug!("Started task {:?}", task_id);
+ self.tcx.dep_graph.read(DepNode::Hir(trait_item_def_id));
+ self.visitor.visit_trait_item(i);
+ debug!("Ended task {:?}", task_id);
+ }
+
fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
let impl_item_def_id = self.tcx.map.local_def_id(i.id);
let task_id = (self.dep_node_fn)(impl_item_def_id);
}
}
+ /// Like `visit_nested_item()`, but for trait items. See
+ /// `visit_nested_item()` for advice on when to override this
+ /// method.
+ #[allow(unused_variables)]
+ fn visit_nested_trait_item(&mut self, id: TraitItemId) {
+ let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id));
+ if let Some(item) = opt_item {
+ self.visit_trait_item(item);
+ }
+ }
+
/// Like `visit_nested_item()`, but for impl items. See
/// `visit_nested_item()` for advice on when to override this
/// method.
/// visit_nested_item, does nothing by default unless you override
/// `nested_visit_map` to return `Some(_)`, in which case it will walk the
/// body.
- fn visit_body(&mut self, id: ExprId) {
- let opt_expr = self.nested_visit_map().intra().map(|map| map.expr(id));
- if let Some(expr) = opt_expr {
- self.visit_expr(expr);
+ fn visit_nested_body(&mut self, id: BodyId) {
+ let opt_body = self.nested_visit_map().intra().map(|map| map.body(id));
+ if let Some(body) = opt_body {
+ self.visit_body(body);
}
}
walk_item(self, i)
}
+ fn visit_body(&mut self, b: &'v Body) {
+ walk_body(self, b);
+ }
+
/// When invoking `visit_all_item_likes()`, you need to supply an
/// item-like visitor. This method converts a "intra-visit"
/// visitor into an item-like visitor that walks the entire tree.
fn visit_expr(&mut self, ex: &'v Expr) {
walk_expr(self, ex)
}
- fn visit_expr_post(&mut self, _ex: &'v Expr) {
- }
fn visit_ty(&mut self, t: &'v Ty) {
walk_ty(self, t)
}
fn visit_where_predicate(&mut self, predicate: &'v WherePredicate) {
walk_where_predicate(self, predicate)
}
- fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: ExprId, s: Span, id: NodeId) {
+ fn visit_fn_decl(&mut self, fd: &'v FnDecl) {
+ walk_fn_decl(self, fd)
+ }
+ fn visit_fn(&mut self, fk: FnKind<'v>, fd: &'v FnDecl, b: BodyId, s: Span, id: NodeId) {
walk_fn(self, fk, fd, b, s, id)
}
fn visit_trait_item(&mut self, ti: &'v TraitItem) {
walk_trait_item(self, ti)
}
+ fn visit_trait_item_ref(&mut self, ii: &'v TraitItemRef) {
+ walk_trait_item_ref(self, ii)
+ }
fn visit_impl_item(&mut self, ii: &'v ImplItem) {
walk_impl_item(self, ii)
}
}
}
+pub fn walk_body<'v, V: Visitor<'v>>(visitor: &mut V, body: &'v Body) {
+ for argument in &body.arguments {
+ visitor.visit_id(argument.id);
+ visitor.visit_pat(&argument.pat);
+ }
+ visitor.visit_expr(&body.value);
+}
+
pub fn walk_local<'v, V: Visitor<'v>>(visitor: &mut V, local: &'v Local) {
visitor.visit_id(local.id);
visitor.visit_pat(&local.pat);
visitor.visit_id(item.id);
visitor.visit_path(path, item.id);
}
- ItemStatic(ref typ, _, ref expr) |
- ItemConst(ref typ, ref expr) => {
+ ItemStatic(ref typ, _, body) |
+ ItemConst(ref typ, body) => {
visitor.visit_id(item.id);
visitor.visit_ty(typ);
- visitor.visit_expr(expr);
+ visitor.visit_nested_body(body);
}
ItemFn(ref declaration, unsafety, constness, abi, ref generics, body_id) => {
visitor.visit_fn(FnKind::ItemFn(item.name,
visitor.visit_generics(type_parameters);
walk_list!(visitor, visit_trait_ref, opt_trait_reference);
visitor.visit_ty(typ);
- for impl_item_ref in impl_item_refs {
- visitor.visit_impl_item_ref(impl_item_ref);
- }
+ walk_list!(visitor, visit_impl_item_ref, impl_item_refs);
}
ItemStruct(ref struct_definition, ref generics) |
ItemUnion(ref struct_definition, ref generics) => {
visitor.visit_id(item.id);
visitor.visit_variant_data(struct_definition, item.name, generics, item.id, item.span);
}
- ItemTrait(_, ref generics, ref bounds, ref methods) => {
+ ItemTrait(_, ref generics, ref bounds, ref trait_item_refs) => {
visitor.visit_id(item.id);
visitor.visit_generics(generics);
walk_list!(visitor, visit_ty_param_bound, bounds);
- walk_list!(visitor, visit_trait_item, methods);
+ walk_list!(visitor, visit_trait_item_ref, trait_item_refs);
}
}
walk_list!(visitor, visit_attribute, &item.attrs);
generics,
parent_item_id,
variant.span);
- walk_list!(visitor, visit_expr, &variant.node.disr_expr);
+ walk_list!(visitor, visit_nested_body, variant.node.disr_expr);
walk_list!(visitor, visit_attribute, &variant.node.attrs);
}
walk_list!(visitor, visit_ty, tuple_element_types);
}
TyBareFn(ref function_declaration) => {
- walk_fn_decl(visitor, &function_declaration.decl);
+ visitor.visit_fn_decl(&function_declaration.decl);
walk_list!(visitor, visit_lifetime_def, &function_declaration.lifetimes);
}
TyPath(ref qpath) => {
visitor.visit_ty(ty);
walk_list!(visitor, visit_ty_param_bound, bounds);
}
- TyArray(ref ty, ref expression) => {
+ TyArray(ref ty, length) => {
visitor.visit_ty(ty);
- visitor.visit_expr(expression)
+ visitor.visit_nested_body(length)
}
TyPolyTraitRef(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
TyImplTrait(ref bounds) => {
walk_list!(visitor, visit_ty_param_bound, bounds);
}
- TyTypeof(ref expression) => {
- visitor.visit_expr(expression)
+ TyTypeof(expression) => {
+ visitor.visit_nested_body(expression)
}
TyInfer => {}
}
visitor.visit_name(foreign_item.span, foreign_item.name);
match foreign_item.node {
- ForeignItemFn(ref function_declaration, ref generics) => {
- walk_fn_decl(visitor, function_declaration);
- visitor.visit_generics(generics)
+ ForeignItemFn(ref function_declaration, ref names, ref generics) => {
+ visitor.visit_generics(generics);
+ visitor.visit_fn_decl(function_declaration);
+ for name in names {
+ visitor.visit_name(name.span, name.node);
+ }
}
ForeignItemStatic(ref typ, _) => visitor.visit_ty(typ),
}
}
pub fn walk_fn_decl<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
- for argument in &function_declaration.inputs {
- visitor.visit_id(argument.id);
- visitor.visit_pat(&argument.pat);
- visitor.visit_ty(&argument.ty)
- }
- walk_fn_ret_ty(visitor, &function_declaration.output)
-}
-
-pub fn walk_fn_decl_nopat<'v, V: Visitor<'v>>(visitor: &mut V, function_declaration: &'v FnDecl) {
- for argument in &function_declaration.inputs {
- visitor.visit_id(argument.id);
- visitor.visit_ty(&argument.ty)
+ for ty in &function_declaration.inputs {
+ visitor.visit_ty(ty)
}
walk_fn_ret_ty(visitor, &function_declaration.output)
}
pub fn walk_fn<'v, V: Visitor<'v>>(visitor: &mut V,
function_kind: FnKind<'v>,
function_declaration: &'v FnDecl,
- body_id: ExprId,
+ body_id: BodyId,
_span: Span,
id: NodeId) {
visitor.visit_id(id);
- walk_fn_decl(visitor, function_declaration);
- walk_fn_kind(visitor, function_kind);
- visitor.visit_body(body_id)
-}
-
-pub fn walk_fn_with_body<'v, V: Visitor<'v>>(visitor: &mut V,
- function_kind: FnKind<'v>,
- function_declaration: &'v FnDecl,
- body: &'v Expr,
- _span: Span,
- id: NodeId) {
- visitor.visit_id(id);
- walk_fn_decl(visitor, function_declaration);
+ visitor.visit_fn_decl(function_declaration);
walk_fn_kind(visitor, function_kind);
- visitor.visit_expr(body)
+ visitor.visit_nested_body(body_id)
}
pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_item: &'v TraitItem) {
visitor.visit_name(trait_item.span, trait_item.name);
walk_list!(visitor, visit_attribute, &trait_item.attrs);
match trait_item.node {
- ConstTraitItem(ref ty, ref default) => {
+ TraitItemKind::Const(ref ty, default) => {
visitor.visit_id(trait_item.id);
visitor.visit_ty(ty);
- walk_list!(visitor, visit_expr, default);
+ walk_list!(visitor, visit_nested_body, default);
}
- MethodTraitItem(ref sig, None) => {
+ TraitItemKind::Method(ref sig, TraitMethod::Required(ref names)) => {
visitor.visit_id(trait_item.id);
visitor.visit_generics(&sig.generics);
- walk_fn_decl(visitor, &sig.decl);
+ visitor.visit_fn_decl(&sig.decl);
+ for name in names {
+ visitor.visit_name(name.span, name.node);
+ }
}
- MethodTraitItem(ref sig, Some(body_id)) => {
+ TraitItemKind::Method(ref sig, TraitMethod::Provided(body_id)) => {
visitor.visit_fn(FnKind::Method(trait_item.name,
sig,
None,
trait_item.span,
trait_item.id);
}
- TypeTraitItem(ref bounds, ref default) => {
+ TraitItemKind::Type(ref bounds, ref default) => {
visitor.visit_id(trait_item.id);
walk_list!(visitor, visit_ty_param_bound, bounds);
walk_list!(visitor, visit_ty, default);
}
}
+pub fn walk_trait_item_ref<'v, V: Visitor<'v>>(visitor: &mut V, trait_item_ref: &'v TraitItemRef) {
+ // NB: Deliberately force a compilation error if/when new fields are added.
+ let TraitItemRef { id, name, ref kind, span, ref defaultness } = *trait_item_ref;
+ visitor.visit_nested_trait_item(id);
+ visitor.visit_name(span, name);
+ visitor.visit_associated_item_kind(kind);
+ visitor.visit_defaultness(defaultness);
+}
+
pub fn walk_impl_item<'v, V: Visitor<'v>>(visitor: &mut V, impl_item: &'v ImplItem) {
// NB: Deliberately force a compilation error if/when new fields are added.
let ImplItem { id: _, name, ref vis, ref defaultness, ref attrs, ref node, span } = *impl_item;
visitor.visit_defaultness(defaultness);
walk_list!(visitor, visit_attribute, attrs);
match *node {
- ImplItemKind::Const(ref ty, ref expr) => {
+ ImplItemKind::Const(ref ty, body) => {
visitor.visit_id(impl_item.id);
visitor.visit_ty(ty);
- visitor.visit_expr(expr);
+ visitor.visit_nested_body(body);
}
ImplItemKind::Method(ref sig, body_id) => {
visitor.visit_fn(FnKind::Method(impl_item.name,
ExprArray(ref subexpressions) => {
walk_list!(visitor, visit_expr, subexpressions);
}
- ExprRepeat(ref element, ref count) => {
+ ExprRepeat(ref element, count) => {
visitor.visit_expr(element);
- visitor.visit_expr(count)
+ visitor.visit_nested_body(count)
}
ExprStruct(ref qpath, ref fields, ref optional_base) => {
visitor.visit_qpath(qpath, expression.id, expression.span);
}
}
}
-
- visitor.visit_expr_post(expression)
}
pub fn walk_arm<'v, V: Visitor<'v>>(visitor: &mut V, arm: &'v Arm) {
self.result.add(id);
}
}
-
-/// Computes the id range for a single fn body, ignoring nested items.
-pub fn compute_id_range_for_fn_body<'v>(fk: FnKind<'v>,
- decl: &'v FnDecl,
- body: &'v Expr,
- sp: Span,
- id: NodeId,
- map: &map::Map<'v>)
- -> IdRange {
- let mut visitor = IdRangeComputingVisitor::new(map);
- walk_fn_with_body(&mut visitor, fk, decl, body, sp, id);
- visitor.result()
-}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::{Item, ImplItem};
+use super::{Item, ImplItem, TraitItem};
use super::intravisit::Visitor;
/// The "item-like visitor" visitor defines only the top-level methods
/// needed.
pub trait ItemLikeVisitor<'hir> {
fn visit_item(&mut self, item: &'hir Item);
+ fn visit_trait_item(&mut self, trait_item: &'hir TraitItem);
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem);
}
self.visitor.visit_item(item);
}
+ fn visit_trait_item(&mut self, trait_item: &'hir TraitItem) {
+ self.visitor.visit_trait_item(trait_item);
+ }
+
fn visit_impl_item(&mut self, impl_item: &'hir ImplItem) {
self.visitor.visit_impl_item(impl_item);
}
use hir::def_id::{DefIndex, DefId};
use hir::def::{Def, PathResolution};
use session::Session;
-use util::nodemap::NodeMap;
-use rustc_data_structures::fnv::FnvHashMap;
+use util::nodemap::{NodeMap, FxHashMap};
use std::collections::BTreeMap;
use std::iter;
-use std::mem;
use syntax::ast::*;
use syntax::errors;
// the form of a DefIndex) so that if we create a new node which introduces
// a definition, then we can properly create the def id.
parent_def: Option<DefIndex>,
- exprs: FnvHashMap<hir::ExprId, hir::Expr>,
resolver: &'a mut Resolver,
/// The items being lowered are collected here.
items: BTreeMap<NodeId, hir::Item>,
+ trait_items: BTreeMap<hir::TraitItemId, hir::TraitItem>,
impl_items: BTreeMap<hir::ImplItemId, hir::ImplItem>,
+ bodies: FxHashMap<hir::BodyId, hir::Body>,
}
pub trait Resolver {
- // Resolve a global hir path generated by the lowerer when expanding `for`, `if let`, etc.
+ // Resolve a hir path generated by the lowerer when expanding `for`, `if let`, etc.
fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool);
// Obtain the resolution for a node id
crate_root: std_inject::injected_crate_name(krate),
sess: sess,
parent_def: None,
- exprs: FnvHashMap(),
resolver: resolver,
items: BTreeMap::new(),
+ trait_items: BTreeMap::new(),
impl_items: BTreeMap::new(),
+ bodies: FxHashMap(),
}.lower_crate(krate)
}
span: c.span,
exported_macros: exported_macros,
items: self.items,
+ trait_items: self.trait_items,
impl_items: self.impl_items,
- exprs: mem::replace(&mut self.exprs, FnvHashMap()),
+ bodies: self.bodies,
}
}
visit::walk_item(self, item);
}
+ fn visit_trait_item(&mut self, item: &'lcx TraitItem) {
+ let id = hir::TraitItemId { node_id: item.id };
+ let hir_item = self.lctx.lower_trait_item(item);
+ self.lctx.trait_items.insert(id, hir_item);
+ visit::walk_trait_item(self, item);
+ }
+
fn visit_impl_item(&mut self, item: &'lcx ImplItem) {
- let id = self.lctx.lower_impl_item_ref(item).id;
+ let id = hir::ImplItemId { node_id: item.id };
let hir_item = self.lctx.lower_impl_item(item);
self.lctx.impl_items.insert(id, hir_item);
visit::walk_impl_item(self, item);
visit::walk_crate(&mut item_lowerer, c);
}
- fn record_expr(&mut self, expr: hir::Expr) -> hir::ExprId {
- let id = hir::ExprId(expr.id);
- self.exprs.insert(id, expr);
+ fn record_body(&mut self, value: hir::Expr, decl: Option<&FnDecl>)
+ -> hir::BodyId {
+ let body = hir::Body {
+ arguments: decl.map_or(hir_vec![], |decl| {
+ decl.inputs.iter().map(|x| self.lower_arg(x)).collect()
+ }),
+ value: value
+ };
+ let id = body.id();
+ self.bodies.insert(id, body);
id
}
P(hir::Ty {
id: t.id,
node: match t.node {
- TyKind::Infer | TyKind::ImplicitSelf => hir::TyInfer,
+ TyKind::Infer => hir::TyInfer,
TyKind::Slice(ref ty) => hir::TySlice(self.lower_ty(ty)),
TyKind::Ptr(ref mt) => hir::TyPtr(self.lower_mt(mt)),
TyKind::Rptr(ref region, ref mt) => {
TyKind::Path(ref qself, ref path) => {
hir::TyPath(self.lower_qpath(t.id, qself, path, ParamMode::Explicit))
}
+ TyKind::ImplicitSelf => {
+ hir::TyPath(hir::QPath::Resolved(None, P(hir::Path {
+ def: self.expect_full_def(t.id),
+ segments: hir_vec![hir::PathSegment {
+ name: keywords::SelfType.name(),
+ parameters: hir::PathParameters::none()
+ }],
+ span: t.span,
+ })))
+ }
TyKind::ObjectSum(ref ty, ref bounds) => {
hir::TyObjectSum(self.lower_ty(ty), self.lower_bounds(bounds))
}
- TyKind::Array(ref ty, ref e) => {
- hir::TyArray(self.lower_ty(ty), P(self.lower_expr(e)))
+ TyKind::Array(ref ty, ref length) => {
+ let length = self.lower_expr(length);
+ hir::TyArray(self.lower_ty(ty),
+ self.record_body(length, None))
}
TyKind::Typeof(ref expr) => {
- hir::TyTypeof(P(self.lower_expr(expr)))
+ let expr = self.lower_expr(expr);
+ hir::TyTypeof(self.record_body(expr, None))
}
TyKind::PolyTraitRef(ref bounds) => {
hir::TyPolyTraitRef(self.lower_bounds(bounds))
name: v.node.name.name,
attrs: self.lower_attrs(&v.node.attrs),
data: self.lower_variant_data(&v.node.data),
- disr_expr: v.node.disr_expr.as_ref().map(|e| P(self.lower_expr(e))),
+ disr_expr: v.node.disr_expr.as_ref().map(|e| {
+ let e = self.lower_expr(e);
+ self.record_body(e, None)
+ }),
},
span: v.span,
}
let proj_start = p.segments.len() - resolution.depth;
let path = P(hir::Path {
- global: p.global,
def: resolution.base_def,
segments: p.segments[..proj_start].iter().enumerate().map(|(i, segment)| {
let param_mode = match (qself_position, param_mode) {
id: NodeId,
p: &Path,
name: Option<Name>,
- param_mode: ParamMode)
+ param_mode: ParamMode,
+ defaults_to_global: bool)
-> hir::Path {
+ let mut segments = p.segments.iter();
+ if defaults_to_global && p.is_global() {
+ segments.next();
+ }
+
hir::Path {
- global: p.global,
def: self.expect_full_def(id),
- segments: p.segments.iter().map(|segment| {
+ segments: segments.map(|segment| {
self.lower_path_segment(segment, param_mode)
}).chain(name.map(|name| {
hir::PathSegment {
fn lower_path(&mut self,
id: NodeId,
p: &Path,
- param_mode: ParamMode)
+ param_mode: ParamMode,
+ defaults_to_global: bool)
-> hir::Path {
- self.lower_path_extra(id, p, None, param_mode)
+ self.lower_path_extra(id, p, None, param_mode, defaults_to_global)
}
fn lower_path_segment(&mut self,
hir::Arg {
id: arg.id,
pat: self.lower_pat(&arg.pat),
- ty: self.lower_ty(&arg.ty),
}
}
+ fn lower_fn_args_to_names(&mut self, decl: &FnDecl)
+ -> hir::HirVec<Spanned<Name>> {
+ decl.inputs.iter().map(|arg| {
+ match arg.pat.node {
+ PatKind::Ident(_, ident, None) => {
+ respan(ident.span, ident.node.name)
+ }
+ _ => respan(arg.pat.span, keywords::Invalid.name()),
+ }
+ }).collect()
+ }
+
fn lower_fn_decl(&mut self, decl: &FnDecl) -> P<hir::FnDecl> {
P(hir::FnDecl {
- inputs: decl.inputs.iter().map(|x| self.lower_arg(x)).collect(),
+ inputs: decl.inputs.iter().map(|arg| self.lower_ty(&arg.ty)).collect(),
output: match decl.output {
FunctionRetTy::Ty(ref ty) => hir::Return(self.lower_ty(ty)),
FunctionRetTy::Default(span) => hir::DefaultReturn(span),
// Check if the where clause type is a plain type parameter.
match bound_pred.bounded_ty.node {
TyKind::Path(None, ref path)
- if !path.global && path.segments.len() == 1 &&
- bound_pred.bound_lifetimes.is_empty() => {
+ if path.segments.len() == 1 &&
+ bound_pred.bound_lifetimes.is_empty() => {
if let Some(Def::TyParam(def_id)) =
self.resolver.get_resolution(bound_pred.bounded_ty.id)
.map(|d| d.base_def) {
span}) => {
hir::WherePredicate::EqPredicate(hir::WhereEqPredicate {
id: id,
- path: self.lower_path(id, path, ParamMode::Explicit),
+ path: self.lower_path(id, path, ParamMode::Explicit, false),
ty: self.lower_ty(ty),
span: span,
})
fn lower_trait_ref(&mut self, p: &TraitRef) -> hir::TraitRef {
hir::TraitRef {
- path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit),
+ path: self.lower_path(p.ref_id, &p.path, ParamMode::Explicit, false),
ref_id: p.ref_id,
}
}
};
let mut path = self.lower_path_extra(import.id, path, suffix,
- ParamMode::Explicit);
+ ParamMode::Explicit, true);
path.span = span;
self.items.insert(import.id, hir::Item {
id: import.id,
path
}
};
- let path = P(self.lower_path(id, path, ParamMode::Explicit));
+ let path = P(self.lower_path(id, path, ParamMode::Explicit, true));
let kind = match view_path.node {
ViewPathSimple(ident, _) => {
*name = ident.name;
hir::ItemUse(path, kind)
}
ItemKind::Static(ref t, m, ref e) => {
+ let value = self.lower_expr(e);
hir::ItemStatic(self.lower_ty(t),
self.lower_mutability(m),
- P(self.lower_expr(e)))
+ self.record_body(value, None))
}
ItemKind::Const(ref t, ref e) => {
- hir::ItemConst(self.lower_ty(t), P(self.lower_expr(e)))
+ let value = self.lower_expr(e);
+ hir::ItemConst(self.lower_ty(t),
+ 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_expr(body);
+ let body_id = self.record_body(body, Some(decl));
hir::ItemFn(self.lower_fn_decl(decl),
self.lower_unsafety(unsafety),
self.lower_constness(constness),
}
ItemKind::Trait(unsafety, ref generics, ref bounds, ref items) => {
let bounds = self.lower_bounds(bounds);
- let items = items.iter().map(|item| self.lower_trait_item(item)).collect();
+ let items = items.iter().map(|item| self.lower_trait_item_ref(item)).collect();
hir::ItemTrait(self.lower_unsafety(unsafety),
self.lower_generics(generics),
bounds,
attrs: this.lower_attrs(&i.attrs),
node: match i.node {
TraitItemKind::Const(ref ty, ref default) => {
- hir::ConstTraitItem(this.lower_ty(ty),
- default.as_ref().map(|x| P(this.lower_expr(x))))
- }
- TraitItemKind::Method(ref sig, ref body) => {
- hir::MethodTraitItem(this.lower_method_sig(sig),
- body.as_ref().map(|x| {
- let body = this.lower_block(x);
- let expr = this.expr_block(body, ThinVec::new());
- this.record_expr(expr)
+ hir::TraitItemKind::Const(this.lower_ty(ty),
+ default.as_ref().map(|x| {
+ let value = this.lower_expr(x);
+ this.record_body(value, None)
}))
}
+ TraitItemKind::Method(ref sig, None) => {
+ let names = this.lower_fn_args_to_names(&sig.decl);
+ hir::TraitItemKind::Method(this.lower_method_sig(sig),
+ hir::TraitMethod::Required(names))
+ }
+ TraitItemKind::Method(ref sig, Some(ref body)) => {
+ let body = this.lower_block(body);
+ let expr = this.expr_block(body, ThinVec::new());
+ let body_id = this.record_body(expr, Some(&sig.decl));
+ hir::TraitItemKind::Method(this.lower_method_sig(sig),
+ hir::TraitMethod::Provided(body_id))
+ }
TraitItemKind::Type(ref bounds, ref default) => {
- hir::TypeTraitItem(this.lower_bounds(bounds),
- default.as_ref().map(|x| this.lower_ty(x)))
+ hir::TraitItemKind::Type(this.lower_bounds(bounds),
+ default.as_ref().map(|x| this.lower_ty(x)))
}
TraitItemKind::Macro(..) => panic!("Shouldn't exist any more"),
},
})
}
+ fn lower_trait_item_ref(&mut self, i: &TraitItem) -> hir::TraitItemRef {
+ let (kind, has_default) = match i.node {
+ TraitItemKind::Const(_, ref default) => {
+ (hir::AssociatedItemKind::Const, default.is_some())
+ }
+ TraitItemKind::Type(_, ref default) => {
+ (hir::AssociatedItemKind::Type, default.is_some())
+ }
+ TraitItemKind::Method(ref sig, ref default) => {
+ (hir::AssociatedItemKind::Method {
+ has_self: sig.decl.has_self(),
+ }, default.is_some())
+ }
+ TraitItemKind::Macro(..) => unimplemented!(),
+ };
+ hir::TraitItemRef {
+ id: hir::TraitItemId { node_id: i.id },
+ name: i.ident.name,
+ span: i.span,
+ defaultness: self.lower_defaultness(Defaultness::Default, has_default),
+ kind: kind,
+ }
+ }
+
fn lower_impl_item(&mut self, i: &ImplItem) -> hir::ImplItem {
self.with_parent_def(i.id, |this| {
hir::ImplItem {
defaultness: this.lower_defaultness(i.defaultness, true /* [1] */),
node: match i.node {
ImplItemKind::Const(ref ty, ref expr) => {
- hir::ImplItemKind::Const(this.lower_ty(ty), P(this.lower_expr(expr)))
+ let value = this.lower_expr(expr);
+ let body_id = this.record_body(value, None);
+ hir::ImplItemKind::Const(this.lower_ty(ty), body_id)
}
ImplItemKind::Method(ref sig, ref body) => {
let body = this.lower_block(body);
let expr = this.expr_block(body, ThinVec::new());
- let expr_id = this.record_expr(expr);
- hir::ImplItemKind::Method(this.lower_method_sig(sig), expr_id)
+ let body_id = this.record_body(expr, Some(&sig.decl));
+ hir::ImplItemKind::Method(this.lower_method_sig(sig), body_id)
}
ImplItemKind::Type(ref ty) => hir::ImplItemKind::Type(this.lower_ty(ty)),
ImplItemKind::Macro(..) => panic!("Shouldn't exist any more"),
ImplItemKind::Const(..) => hir::AssociatedItemKind::Const,
ImplItemKind::Type(..) => hir::AssociatedItemKind::Type,
ImplItemKind::Method(ref sig, _) => hir::AssociatedItemKind::Method {
- has_self: sig.decl.get_self().is_some(),
+ has_self: sig.decl.has_self(),
},
ImplItemKind::Macro(..) => unimplemented!(),
},
attrs: this.lower_attrs(&i.attrs),
node: match i.node {
ForeignItemKind::Fn(ref fdec, ref generics) => {
- hir::ForeignItemFn(this.lower_fn_decl(fdec), this.lower_generics(generics))
+ hir::ForeignItemFn(this.lower_fn_decl(fdec),
+ this.lower_fn_args_to_names(fdec),
+ this.lower_generics(generics))
}
ForeignItemKind::Static(ref t, m) => {
hir::ForeignItemStatic(this.lower_ty(t), m)
}
fn lower_method_sig(&mut self, sig: &MethodSig) -> hir::MethodSig {
- let hir_sig = hir::MethodSig {
+ hir::MethodSig {
generics: self.lower_generics(&sig.generics),
abi: sig.abi,
unsafety: self.lower_unsafety(sig.unsafety),
constness: self.lower_constness(sig.constness),
decl: self.lower_fn_decl(&sig.decl),
- };
- // Check for `self: _` and `self: &_`
- if let Some(SelfKind::Explicit(..)) = sig.decl.get_self().map(|eself| eself.node) {
- match hir_sig.decl.get_self().map(|eself| eself.node) {
- Some(hir::SelfKind::Value(..)) | Some(hir::SelfKind::Region(..)) => {
- self.diagnostic().span_err(sig.decl.inputs[0].ty.span,
- "the type placeholder `_` is not allowed within types on item signatures");
- }
- _ => {}
- }
}
- hir_sig
}
fn lower_unsafety(&mut self, u: Unsafety) -> hir::Unsafety {
Some(def) => {
hir::PatKind::Path(hir::QPath::Resolved(None, P(hir::Path {
span: pth1.span,
- global: false,
def: def,
segments: hir_vec![
hir::PathSegment::from_name(pth1.node.name)
}
ExprKind::Repeat(ref expr, ref count) => {
let expr = P(self.lower_expr(expr));
- let count = P(self.lower_expr(count));
- hir::ExprRepeat(expr, count)
+ let count = self.lower_expr(count);
+ hir::ExprRepeat(expr, self.record_body(count, None))
}
ExprKind::Tup(ref elts) => {
hir::ExprTup(elts.iter().map(|x| self.lower_expr(x)).collect())
let expr = this.lower_expr(body);
hir::ExprClosure(this.lower_capture_clause(capture_clause),
this.lower_fn_decl(decl),
- this.record_expr(expr),
+ this.record_body(expr, Some(decl)),
fn_decl_span)
})
}
// `::std::option::Option::Some(<pat>) => <body>`
let pat_arm = {
let body_block = self.lower_block(body);
- let body_span = body_block.span;
- let body_expr = P(hir::Expr {
- id: self.next_id(),
- node: hir::ExprBlock(body_block),
- span: body_span,
- attrs: ThinVec::new(),
- });
+ 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);
Visibility::Crate(_) => hir::Visibility::Crate,
Visibility::Restricted { ref path, id } => {
hir::Visibility::Restricted {
- path: P(self.lower_path(id, path, ParamMode::Explicit)),
+ path: P(self.lower_path(id, path, ParamMode::Explicit, true)),
id: id
}
}
let expr_path = hir::ExprPath(hir::QPath::Resolved(None, P(hir::Path {
span: span,
- global: false,
def: def,
segments: hir_vec![hir::PathSegment::from_name(id)],
})));
/// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
/// The path is also resolved according to `is_value`.
fn std_path(&mut self, span: Span, components: &[&str], is_value: bool) -> hir::Path {
- let idents = self.crate_root.iter().chain(components);
-
- let segments: Vec<_> = idents.map(|name| {
- hir::PathSegment::from_name(Symbol::intern(name))
- }).collect();
-
let mut path = hir::Path {
span: span,
- global: true,
def: Def::Err,
- segments: segments.into(),
+ segments: iter::once(keywords::CrateRoot.name()).chain({
+ self.crate_root.into_iter().chain(components.iter().cloned()).map(Symbol::intern)
+ }).map(hir::PathSegment::from_name).collect(),
};
self.resolver.resolve_hir_path(&mut path, is_value);
/// Components shared by fn-like things (fn items, methods, closures).
pub struct FnParts<'a> {
pub decl: &'a FnDecl,
- pub body: ast::ExprId,
+ pub body: ast::BodyId,
pub kind: FnKind<'a>,
pub span: Span,
pub id: NodeId,
impl MaybeFnLike for ast::TraitItem {
fn is_fn_like(&self) -> bool {
- match self.node { ast::MethodTraitItem(_, Some(_)) => true, _ => false, }
+ match self.node {
+ ast::TraitItemKind::Method(_, ast::TraitMethod::Provided(_)) => true,
+ _ => false,
+ }
}
}
abi: abi::Abi,
vis: &'a ast::Visibility,
generics: &'a ast::Generics,
- body: ast::ExprId,
+ body: ast::BodyId,
id: NodeId,
span: Span,
attrs: &'a [Attribute],
/// for use when implementing FnLikeNode operations.
struct ClosureParts<'a> {
decl: &'a FnDecl,
- body: ast::ExprId,
+ body: ast::BodyId,
id: NodeId,
span: Span,
attrs: &'a [Attribute],
}
impl<'a> ClosureParts<'a> {
- fn new(d: &'a FnDecl, b: ast::ExprId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
+ fn new(d: &'a FnDecl, b: ast::BodyId, id: NodeId, s: Span, attrs: &'a [Attribute]) -> Self {
ClosureParts {
decl: d,
body: b,
}
}
- pub fn body(self) -> ast::ExprId {
+ pub fn body(self) -> ast::BodyId {
self.handle(|i: ItemFnParts<'a>| i.body,
- |_, _, _: &'a ast::MethodSig, _, body: ast::ExprId, _, _| body,
+ |_, _, _: &'a ast::MethodSig, _, body: ast::BodyId, _, _| body,
|c: ClosureParts<'a>| c.body)
}
Name,
&'a ast::MethodSig,
Option<&'a ast::Visibility>,
- ast::ExprId,
+ ast::BodyId,
Span,
&'a [Attribute])
-> A,
_ => bug!("item FnLikeNode that is not fn-like"),
},
map::NodeTraitItem(ti) => match ti.node {
- ast::MethodTraitItem(ref sig, Some(body)) => {
+ ast::TraitItemKind::Method(ref sig, ast::TraitMethod::Provided(body)) => {
method(ti.id, ti.name, sig, None, body, ti.span, &ti.attrs)
}
_ => bug!("trait method FnLikeNode that is not fn-like"),
use super::*;
use hir::intravisit::{Visitor, NestedVisitorMap};
-use middle::cstore::InlinedItem;
use std::iter::repeat;
use syntax::ast::{NodeId, CRATE_NODE_ID};
use syntax_pos::Span;
/// The crate
pub krate: &'ast Crate,
/// The node map
- pub map: Vec<MapEntry<'ast>>,
+ pub(super) map: Vec<MapEntry<'ast>>,
/// The parent of this node
pub parent_node: NodeId,
/// If true, completely ignore nested items. We set this when loading
collector
}
- pub fn extend(krate: &'ast Crate,
- parent: &'ast InlinedItem,
- parent_node: NodeId,
- map: Vec<MapEntry<'ast>>)
- -> NodeCollector<'ast> {
+ pub(super) fn extend(krate: &'ast Crate,
+ parent: &'ast InlinedItem,
+ parent_node: NodeId,
+ map: Vec<MapEntry<'ast>>)
+ -> NodeCollector<'ast> {
let mut collector = NodeCollector {
krate: krate,
map: map,
}
}
+ fn visit_nested_trait_item(&mut self, item_id: TraitItemId) {
+ if !self.ignore_nested_items {
+ self.visit_trait_item(self.krate.trait_item(item_id))
+ }
+ }
+
fn visit_nested_impl_item(&mut self, item_id: ImplItemId) {
- self.visit_impl_item(self.krate.impl_item(item_id))
+ if !self.ignore_nested_items {
+ self.visit_impl_item(self.krate.impl_item(item_id))
+ }
}
- fn visit_body(&mut self, id: ExprId) {
- self.visit_expr(self.krate.expr(id))
+ fn visit_nested_body(&mut self, id: BodyId) {
+ if !self.ignore_nested_items {
+ self.visit_body(self.krate.body(id))
+ }
}
fn visit_item(&mut self, i: &'ast Item) {
self.with_parent(i.id, |this| {
match i.node {
- ItemEnum(ref enum_definition, _) => {
- for v in &enum_definition.variants {
- this.insert(v.node.data.id(), NodeVariant(v));
- }
- }
ItemStruct(ref struct_def, _) => {
// If this is a tuple-like struct, register the constructor.
if !struct_def.is_struct() {
}
fn visit_fn(&mut self, fk: intravisit::FnKind<'ast>, fd: &'ast FnDecl,
- b: ExprId, s: Span, id: NodeId) {
+ b: BodyId, s: Span, id: NodeId) {
assert_eq!(self.parent_node, id);
intravisit::walk_fn(self, fk, fd, b, s, id);
}
self.insert_entry(macro_def.id, NotPresent);
}
+ fn visit_variant(&mut self, v: &'ast Variant, g: &'ast Generics, item_id: NodeId) {
+ let id = v.node.data.id();
+ self.insert(id, NodeVariant(v));
+ self.with_parent(id, |this| {
+ intravisit::walk_variant(this, v, g, item_id);
+ });
+ }
+
fn visit_struct_field(&mut self, field: &'ast StructField) {
self.insert(field.id, NodeField(field));
self.with_parent(field.id, |this| {
use syntax::visit;
use syntax::symbol::{Symbol, keywords};
-/// Creates def ids for nodes in the HIR.
+/// Creates def ids for nodes in the AST.
pub struct DefCollector<'a> {
definitions: &'a mut Definitions,
parent_def: Option<DefIndex>,
}
}
-
#[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
pub enum DefPathData {
// Root: these should only be used for the root nodes, because
data,
self.table.def_key(self.node_to_def_index[&node_id]));
- assert!(parent.is_some() ^ (data == DefPathData::CrateRoot));
+ assert_eq!(parent.is_some(), data != DefPathData::CrateRoot);
// Find a unique DefKey. This basically means incrementing the disambiguator
// until we get no match.
use dep_graph::{DepGraph, DepNode};
-use middle::cstore::InlinedItem;
use hir::def_id::{CRATE_DEF_INDEX, DefId, DefIndex};
use syntax::abi::Abi;
use syntax_pos::Span;
use hir::*;
-use hir::print as pprust;
+use hir::intravisit::Visitor;
+use hir::print::Nested;
use arena::TypedArena;
use std::cell::RefCell;
mod def_collector;
pub mod definitions;
+/// The data we save and restore about an inlined item or method. This is not
+/// part of the AST that we parse from a file, but it becomes part of the tree
+/// that we trans.
+#[derive(Debug)]
+struct InlinedItem {
+ def_id: DefId,
+ body: Body,
+}
+
#[derive(Copy, Clone, Debug)]
pub enum Node<'ast> {
NodeItem(&'ast Item),
NodeLifetime(&'ast Lifetime),
NodeTyParam(&'ast TyParam),
NodeVisibility(&'ast Visibility),
-
- NodeInlinedItem(&'ast InlinedItem),
}
/// Represents an entry and its parent NodeID.
/// The odd layout is to bring down the total size.
#[derive(Copy, Debug)]
-pub enum MapEntry<'ast> {
+enum MapEntry<'ast> {
/// Placeholder for holes in the map.
NotPresent,
NodeLifetime(n) => EntryLifetime(p, n),
NodeTyParam(n) => EntryTyParam(p, n),
NodeVisibility(n) => EntryVisibility(p, n),
-
- NodeInlinedItem(n) => RootInlinedParent(n),
}
}
EntryLifetime(_, n) => NodeLifetime(n),
EntryTyParam(_, n) => NodeTyParam(n),
EntryVisibility(_, n) => NodeVisibility(n),
- RootInlinedParent(n) => NodeInlinedItem(n),
_ => return None
})
}
+
+ fn is_body_owner(self, node_id: NodeId) -> bool {
+ match self {
+ EntryItem(_, item) => {
+ match item.node {
+ ItemConst(_, body) |
+ ItemStatic(.., body) |
+ ItemFn(_, _, _, _, _, body) => body.node_id == node_id,
+ _ => false
+ }
+ }
+
+ EntryTraitItem(_, item) => {
+ match item.node {
+ TraitItemKind::Const(_, Some(body)) |
+ TraitItemKind::Method(_, TraitMethod::Provided(body)) => {
+ body.node_id == node_id
+ }
+ _ => false
+ }
+ }
+
+ EntryImplItem(_, item) => {
+ match item.node {
+ ImplItemKind::Const(_, body) |
+ ImplItemKind::Method(_, body) => body.node_id == node_id,
+ _ => false
+ }
+ }
+
+ EntryExpr(_, expr) => {
+ match expr.node {
+ ExprClosure(.., body, _) => body.node_id == node_id,
+ _ => false
+ }
+ }
+
+ _ => false
+ }
+ }
}
/// Stores a crate and any number of inlined items from other crates.
if !self.is_inlined_node_id(id) {
let mut last_expr = None;
loop {
- match map[id.as_usize()] {
- EntryItem(_, item) => {
- assert_eq!(id, item.id);
- let def_id = self.local_def_id(id);
-
+ let entry = map[id.as_usize()];
+ match entry {
+ EntryItem(..) |
+ EntryTraitItem(..) |
+ EntryImplItem(..) => {
if let Some(last_id) = last_expr {
- // The body of the item may have a separate dep node
- // (Note that trait items don't currently have
- // their own dep node, so there's also just one
- // HirBody node for all the items)
- if self.is_body(last_id, item) {
+ // The body may have a separate dep node
+ if entry.is_body_owner(last_id) {
+ let def_id = self.local_def_id(id);
return DepNode::HirBody(def_id);
}
}
- return DepNode::Hir(def_id);
+ return DepNode::Hir(self.local_def_id(id));
}
- EntryImplItem(_, item) => {
- let def_id = self.local_def_id(id);
+ EntryVariant(p, v) => {
+ id = p;
- if let Some(last_id) = last_expr {
- // The body of the item may have a separate dep node
- if self.is_impl_item_body(last_id, item) {
+ if last_expr.is_some() {
+ if v.node.disr_expr.map(|e| e.node_id) == last_expr {
+ // The enum parent holds both Hir and HirBody nodes.
+ let def_id = self.local_def_id(id);
return DepNode::HirBody(def_id);
}
}
- return DepNode::Hir(def_id);
}
EntryForeignItem(p, _) |
- EntryTraitItem(p, _) |
- EntryVariant(p, _) |
EntryField(p, _) |
EntryStmt(p, _) |
EntryTy(p, _) |
bug!("node {} has inlined ancestor but is not inlined", id0),
NotPresent =>
- // Some nodes, notably struct fields, are not
+ // Some nodes, notably macro definitions, are not
// present in the map for whatever reason, but
// they *do* have def-ids. So if we encounter an
// empty hole, check for that case.
}
}
- fn is_body(&self, node_id: NodeId, item: &Item) -> bool {
- match item.node {
- ItemFn(_, _, _, _, _, body) => body.node_id() == node_id,
- // Since trait items currently don't get their own dep nodes,
- // we check here whether node_id is the body of any of the items.
- // If they get their own dep nodes, this can go away
- ItemTrait(_, _, _, ref trait_items) => {
- trait_items.iter().any(|trait_item| { match trait_item.node {
- MethodTraitItem(_, Some(body)) => body.node_id() == node_id,
- _ => false
- }})
- }
- _ => false
- }
- }
-
- fn is_impl_item_body(&self, node_id: NodeId, item: &ImplItem) -> bool {
- match item.node {
- ImplItemKind::Method(_, body) => body.node_id() == node_id,
- _ => false
- }
- }
-
pub fn num_local_def_ids(&self) -> usize {
self.definitions.len()
}
self.forest.krate()
}
+ pub fn trait_item(&self, id: TraitItemId) -> &'ast TraitItem {
+ self.read(id.node_id);
+
+ // NB: intentionally bypass `self.forest.krate()` so that we
+ // do not trigger a read of the whole krate here
+ self.forest.krate.trait_item(id)
+ }
+
pub fn impl_item(&self, id: ImplItemId) -> &'ast ImplItem {
self.read(id.node_id);
self.forest.krate.impl_item(id)
}
+ pub fn body(&self, id: BodyId) -> &'ast Body {
+ self.read(id.node_id);
+
+ // NB: intentionally bypass `self.forest.krate()` so that we
+ // do not trigger a read of the whole krate here
+ self.forest.krate.body(id)
+ }
+
+ /// Returns the `NodeId` that corresponds to the definition of
+ /// which this is the body of, i.e. a `fn`, `const` or `static`
+ /// item (possibly associated), or a closure, or the body itself
+ /// for embedded constant expressions (e.g. `N` in `[T; N]`).
+ pub fn body_owner(&self, BodyId { node_id }: BodyId) -> NodeId {
+ let parent = self.get_parent_node(node_id);
+ if self.map.borrow()[parent.as_usize()].is_body_owner(node_id) {
+ parent
+ } else {
+ node_id
+ }
+ }
+
+ pub fn body_owner_def_id(&self, id: BodyId) -> DefId {
+ self.local_def_id(self.body_owner(id))
+ }
+
/// Get the attributes on the krate. This is preferable to
/// invoking `krate.attrs` because it registers a tighter
/// dep-graph access.
}
}
- pub fn expect_inlined_item(&self, id: NodeId) -> &'ast InlinedItem {
+ pub fn expect_inlined_body(&self, id: NodeId) -> &'ast Body {
match self.find_entry(id) {
- Some(RootInlinedParent(inlined_item)) => inlined_item,
+ Some(RootInlinedParent(inlined_item)) => &inlined_item.body,
_ => bug!("expected inlined item, found {}", self.node_to_string(id)),
}
}
- pub fn expr(&self, id: ExprId) -> &'ast Expr {
- self.expect_expr(id.node_id())
- }
-
/// Returns the name associated with the given NodeId's AST.
pub fn name(&self, id: NodeId) -> Name {
match self.get(id) {
Some(EntryVisibility(_, v)) => bug!("unexpected Visibility {:?}", v),
Some(RootCrate) => self.forest.krate.span,
- Some(RootInlinedParent(parent)) => parent.body.span,
+ Some(RootInlinedParent(parent)) => parent.body.value.span,
Some(NotPresent) | None => {
bug!("hir::map::Map::span: id not in map: {:?}", id)
}
pub fn node_to_user_string(&self, id: NodeId) -> String {
node_id_to_string(self, id, false)
}
+
+ pub fn node_to_pretty_string(&self, id: NodeId) -> String {
+ print::to_string(self, |s| s.print_node(self.get(id)))
+ }
}
pub struct NodesMatchingSuffix<'a, 'ast:'a> {
}
}
-/// Used for items loaded from external crate that are being inlined into this
+/// Used for bodies loaded from external crate that are being inlined into this
/// crate.
-pub fn map_decoded_item<'ast>(map: &Map<'ast>,
- ii: InlinedItem,
- ii_parent_id: NodeId)
- -> &'ast InlinedItem {
+pub fn map_decoded_body<'ast>(map: &Map<'ast>,
+ def_id: DefId,
+ body: Body,
+ parent_id: NodeId)
+ -> &'ast Body {
let _ignore = map.forest.dep_graph.in_ignore();
- let ii = map.forest.inlined_items.alloc(ii);
+ let ii = map.forest.inlined_items.alloc(InlinedItem {
+ def_id: def_id,
+ body: body
+ });
let mut collector = NodeCollector::extend(map.krate(),
ii,
- ii_parent_id,
+ parent_id,
mem::replace(&mut *map.map.borrow_mut(), vec![]));
- ii.visit(&mut collector);
+ collector.visit_body(&ii.body);
*map.map.borrow_mut() = collector.map;
- ii
+ &ii.body
}
-pub trait NodePrinter {
- fn print_node(&mut self, node: &Node) -> io::Result<()>;
+/// Identical to the `PpAnn` implementation for `hir::Crate`,
+/// except it avoids creating a dependency on the whole crate.
+impl<'ast> print::PpAnn for Map<'ast> {
+ fn nested(&self, state: &mut print::State, nested: print::Nested) -> io::Result<()> {
+ match nested {
+ Nested::Item(id) => state.print_item(self.expect_item(id.id)),
+ Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
+ Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
+ Nested::Body(id) => state.print_expr(&self.body(id).value),
+ Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat)
+ }
+ }
}
-impl<'a> NodePrinter for pprust::State<'a> {
- fn print_node(&mut self, node: &Node) -> io::Result<()> {
- match *node {
+impl<'a> print::State<'a> {
+ pub fn print_node(&mut self, node: Node) -> io::Result<()> {
+ match node {
NodeItem(a) => self.print_item(&a),
NodeForeignItem(a) => self.print_foreign_item(&a),
NodeTraitItem(a) => self.print_trait_item(a),
NodeStmt(a) => self.print_stmt(&a),
NodeTy(a) => self.print_type(&a),
NodeTraitRef(a) => self.print_trait_ref(&a),
+ NodeLocal(a) |
NodePat(a) => self.print_pat(&a),
- NodeBlock(a) => self.print_block(&a),
+ NodeBlock(a) => {
+ use syntax::print::pprust::PrintState;
+
+ // containing cbox, will be closed by print-block at }
+ self.cbox(print::indent_unit)?;
+ // head-ibox, will be closed by print-block after {
+ self.ibox(0)?;
+ self.print_block(&a)
+ }
NodeLifetime(a) => self.print_lifetime(&a),
NodeVisibility(a) => self.print_visibility(&a),
NodeTyParam(_) => bug!("cannot print TyParam"),
// these cases do not carry enough information in the
// ast_map to reconstruct their full structure for pretty
// printing.
- NodeLocal(_) => bug!("cannot print isolated Local"),
NodeStructCtor(_) => bug!("cannot print isolated StructCtor"),
-
- NodeInlinedItem(_) => bug!("cannot print inlined item"),
}
}
}
}
Some(NodeTraitItem(ti)) => {
let kind = match ti.node {
- ConstTraitItem(..) => "assoc constant",
- MethodTraitItem(..) => "trait method",
- TypeTraitItem(..) => "assoc type",
+ TraitItemKind::Const(..) => "assoc constant",
+ TraitItemKind::Method(..) => "trait method",
+ TraitItemKind::Type(..) => "assoc type",
};
format!("{} {} in {}{}", kind, ti.name, path_str(), id_str)
field.name,
path_str(), id_str)
}
- Some(NodeExpr(ref expr)) => {
- format!("expr {}{}", pprust::expr_to_string(&expr), id_str)
+ Some(NodeExpr(_)) => {
+ format!("expr {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeStmt(ref stmt)) => {
- format!("stmt {}{}", pprust::stmt_to_string(&stmt), id_str)
+ Some(NodeStmt(_)) => {
+ format!("stmt {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeTy(ref ty)) => {
- format!("type {}{}", pprust::ty_to_string(&ty), id_str)
+ Some(NodeTy(_)) => {
+ format!("type {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeTraitRef(ref tr)) => {
- format!("trait_ref {}{}", pprust::path_to_string(&tr.path), id_str)
+ Some(NodeTraitRef(_)) => {
+ format!("trait_ref {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeLocal(ref pat)) => {
- format!("local {}{}", pprust::pat_to_string(&pat), id_str)
+ Some(NodeLocal(_)) => {
+ format!("local {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodePat(ref pat)) => {
- format!("pat {}{}", pprust::pat_to_string(&pat), id_str)
+ Some(NodePat(_)) => {
+ format!("pat {}{}", map.node_to_pretty_string(id), id_str)
}
- Some(NodeBlock(ref block)) => {
- format!("block {}{}", pprust::block_to_string(&block), id_str)
+ Some(NodeBlock(_)) => {
+ format!("block {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeStructCtor(_)) => {
format!("struct_ctor {}{}", path_str(), id_str)
}
- Some(NodeLifetime(ref l)) => {
- format!("lifetime {}{}",
- pprust::lifetime_to_string(&l), id_str)
+ Some(NodeLifetime(_)) => {
+ format!("lifetime {}{}", map.node_to_pretty_string(id), id_str)
}
Some(NodeTyParam(ref ty_param)) => {
format!("typaram {:?}{}", ty_param, id_str)
Some(NodeVisibility(ref vis)) => {
format!("visibility {:?}{}", vis, id_str)
}
- Some(NodeInlinedItem(_)) => {
- format!("inlined item {}", id_str)
- }
None => {
format!("unknown node{}", id_str)
}
pub use self::Mutability::*;
pub use self::PrimTy::*;
pub use self::Stmt_::*;
-pub use self::TraitItem_::*;
pub use self::Ty_::*;
pub use self::TyParamBound::*;
pub use self::UnOp::*;
use hir::def::Def;
use hir::def_id::DefId;
-use util::nodemap::{NodeMap, FxHashSet};
-use rustc_data_structures::fnv::FnvHashMap;
+use util::nodemap::{NodeMap, FxHashMap, FxHashSet};
-use syntax_pos::{mk_sp, Span, ExpnId, DUMMY_SP};
-use syntax::codemap::{self, respan, Spanned};
+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::{Attribute, Lit, StrStyle, FloatTy, IntTy, UintTy, MetaItem};
write!(f,
"lifetime({}: {})",
self.id,
- print::lifetime_to_string(self))
+ print::to_string(print::NO_ANN, |s| s.print_lifetime(self)))
}
}
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
pub struct Path {
pub span: Span,
- /// A `::foo` path, is relative to the crate root rather than current
- /// module (like paths in an import).
- pub global: bool,
/// The definition that the path resolved to.
pub def: Def,
/// The segments in the path: the things separated by `::`.
pub segments: HirVec<PathSegment>,
}
-impl fmt::Debug for Path {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "path({})", print::path_to_string(self))
+impl Path {
+ pub fn is_global(&self) -> bool {
+ !self.segments.is_empty() && self.segments[0].name == keywords::CrateRoot.name()
}
}
-impl fmt::Display for Path {
+impl fmt::Debug for Path {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", print::path_to_string(self))
+ write!(f, "path({})",
+ print::to_string(print::NO_ANN, |s| s.print_path(self, false)))
}
}
// slightly different results.
pub items: BTreeMap<NodeId, Item>,
+ pub trait_items: BTreeMap<TraitItemId, TraitItem>,
pub impl_items: BTreeMap<ImplItemId, ImplItem>,
- pub exprs: FnvHashMap<ExprId, Expr>,
+ pub bodies: FxHashMap<BodyId, Body>,
}
impl Crate {
&self.items[&id]
}
+ pub fn trait_item(&self, id: TraitItemId) -> &TraitItem {
+ &self.trait_items[&id]
+ }
+
pub fn impl_item(&self, id: ImplItemId) -> &ImplItem {
&self.impl_items[&id]
}
visitor.visit_item(item);
}
+ for (_, trait_item) in &self.trait_items {
+ visitor.visit_trait_item(trait_item);
+ }
+
for (_, impl_item) in &self.impl_items {
visitor.visit_impl_item(impl_item);
}
}
- pub fn expr(&self, id: ExprId) -> &Expr {
- &self.exprs[&id]
+ pub fn body(&self, id: BodyId) -> &Body {
+ &self.bodies[&id]
}
}
impl fmt::Debug for Pat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "pat({}: {})", self.id, print::pat_to_string(self))
+ write!(f, "pat({}: {})", self.id,
+ print::to_string(print::NO_ANN, |s| s.print_pat(self)))
}
}
write!(f,
"stmt({}: {})",
spanned.node.id(),
- print::stmt_to_string(&spanned))
+ print::to_string(print::NO_ANN, |s| s.print_stmt(&spanned)))
}
}
UserProvided,
}
-#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct ExprId(NodeId);
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct BodyId {
+ pub node_id: NodeId,
+}
+
+/// The body of a function or constant value.
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct Body {
+ pub arguments: HirVec<Arg>,
+ pub value: Expr
+}
-impl ExprId {
- pub fn node_id(self) -> NodeId {
- self.0
+impl Body {
+ pub fn id(&self) -> BodyId {
+ BodyId {
+ node_id: self.value.id
+ }
}
}
pub attrs: ThinVec<Attribute>,
}
-impl Expr {
- pub fn expr_id(&self) -> ExprId {
- ExprId(self.id)
- }
-}
-
impl fmt::Debug for Expr {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "expr({}: {})", self.id, print::expr_to_string(self))
+ write!(f, "expr({}: {})", self.id,
+ print::to_string(print::NO_ANN, |s| s.print_expr(self)))
}
}
/// A closure (for example, `move |a, b, c| {a + b + c}`).
///
/// The final span is the span of the argument block `|...|`
- ExprClosure(CaptureClause, P<FnDecl>, ExprId, Span),
+ ExprClosure(CaptureClause, P<FnDecl>, BodyId, Span),
/// A block (`{ ... }`)
ExprBlock(P<Block>),
///
/// For example, `[1; 5]`. The first expression is the element
/// to be repeated; the second is the number of times to repeat it.
- ExprRepeat(P<Expr>, P<Expr>),
+ ExprRepeat(P<Expr>, BodyId),
}
/// Optionally `Self`-qualified value/type path or associated extension.
TypeRelative(P<Ty>, P<PathSegment>)
}
-impl fmt::Display for QPath {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "{}", print::qpath_to_string(self))
- }
-}
-
/// Hints at the original code for a `match _ { .. }`
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
pub enum MatchSource {
pub generics: Generics,
}
+// The bodies for items are stored "out of line", in a separate
+// hashmap in the `Crate`. Here we just record the node-id of the item
+// so it can fetched later.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TraitItemId {
+ pub node_id: NodeId,
+}
+
/// Represents an item declaration within a trait declaration,
/// possibly including a default implementation. A trait item is
/// either required (meaning it doesn't have an implementation, just a
pub id: NodeId,
pub name: Name,
pub attrs: HirVec<Attribute>,
- pub node: TraitItem_,
+ pub node: TraitItemKind,
pub span: Span,
}
+/// A trait method's body (or just argument names).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub enum TraitMethod {
+ /// No default body in the trait, just a signature.
+ Required(HirVec<Spanned<Name>>),
+
+ /// Both signature and body are provided in the trait.
+ Provided(BodyId),
+}
+
/// Represents a trait method or associated constant or type
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum TraitItem_ {
+pub enum TraitItemKind {
/// An associated constant with an optional value (otherwise `impl`s
/// must contain a value)
- ConstTraitItem(P<Ty>, Option<P<Expr>>),
+ Const(P<Ty>, Option<BodyId>),
/// A method with an optional body
- MethodTraitItem(MethodSig, Option<ExprId>),
+ Method(MethodSig, TraitMethod),
/// An associated type with (possibly empty) bounds and optional concrete
/// type
- TypeTraitItem(TyParamBounds, Option<P<Ty>>),
+ Type(TyParamBounds, Option<P<Ty>>),
}
// The bodies for items are stored "out of line", in a separate
pub enum ImplItemKind {
/// An associated constant of the given type, set to the constant result
/// of the expression
- Const(P<Ty>, P<Expr>),
+ Const(P<Ty>, BodyId),
/// A method implementation with the given signature and body
- Method(MethodSig, ExprId),
+ Method(MethodSig, BodyId),
/// An associated type
Type(P<Ty>),
}
impl fmt::Debug for Ty {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(f, "type({})", print::ty_to_string(self))
+ write!(f, "type({})",
+ print::to_string(print::NO_ANN, |s| s.print_type(self)))
}
}
/// A variable length slice (`[T]`)
TySlice(P<Ty>),
/// A fixed length array (`[T; n]`)
- TyArray(P<Ty>, P<Expr>),
+ TyArray(P<Ty>, BodyId),
/// A raw pointer (`*const T` or `*mut T`)
TyPtr(MutTy),
/// A reference (`&'a T` or `&'a mut T`)
/// An `impl TraitA+TraitB` type.
TyImplTrait(TyParamBounds),
/// Unused for now
- TyTypeof(P<Expr>),
+ TyTypeof(BodyId),
/// TyInfer means the type should be inferred instead of it having been
/// specified. This can appear anywhere in a type.
TyInfer,
/// represents an argument in a function header
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct Arg {
- pub ty: P<Ty>,
pub pat: P<Pat>,
pub id: NodeId,
}
-/// Alternative representation for `Arg`s describing `self` parameter of methods.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub enum SelfKind {
- /// `self`, `mut self`
- Value(Mutability),
- /// `&'lt self`, `&'lt mut self`
- Region(Option<Lifetime>, Mutability),
- /// `self: TYPE`, `mut self: TYPE`
- Explicit(P<Ty>, Mutability),
-}
-
-pub type ExplicitSelf = Spanned<SelfKind>;
-
-impl Arg {
- pub fn to_self(&self) -> Option<ExplicitSelf> {
- if let PatKind::Binding(BindByValue(mutbl), _, name, _) = self.pat.node {
- if name.node == keywords::SelfValue.name() {
- return match self.ty.node {
- TyInfer => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
- TyRptr(lt, MutTy{ref ty, mutbl}) if ty.node == TyInfer => {
- Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
- }
- _ => Some(respan(mk_sp(self.pat.span.lo, self.ty.span.hi),
- SelfKind::Explicit(self.ty.clone(), mutbl)))
- }
- }
- }
- None
- }
-
- pub fn is_self(&self) -> bool {
- if let PatKind::Binding(_, _, name, _) = self.pat.node {
- name.node == keywords::SelfValue.name()
- } else {
- false
- }
- }
-}
-
/// Represents the header (not the body) of a function declaration
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub struct FnDecl {
- pub inputs: HirVec<Arg>,
+ pub inputs: HirVec<P<Ty>>,
pub output: FunctionRetTy,
pub variadic: bool,
}
-impl FnDecl {
- pub fn get_self(&self) -> Option<ExplicitSelf> {
- self.inputs.get(0).and_then(Arg::to_self)
- }
- pub fn has_self(&self) -> bool {
- self.inputs.get(0).map(Arg::is_self).unwrap_or(false)
- }
-}
-
#[derive(Copy, Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum Unsafety {
Unsafe,
pub attrs: HirVec<Attribute>,
pub data: VariantData,
/// Explicit discriminant, eg `Foo = 1`
- pub disr_expr: Option<P<Expr>>,
+ pub disr_expr: Option<BodyId>,
}
pub type Variant = Spanned<Variant_>;
pub id: NodeId,
}
-// FIXME (#3300): Should allow items to be anonymous. Right now
-// we just use dummy names for anon items.
/// An item
///
/// The name might be a dummy name in case of anonymous items
ItemUse(P<Path>, UseKind),
/// A `static` item
- ItemStatic(P<Ty>, Mutability, P<Expr>),
+ ItemStatic(P<Ty>, Mutability, BodyId),
/// A `const` item
- ItemConst(P<Ty>, P<Expr>),
+ ItemConst(P<Ty>, BodyId),
/// A function declaration
- ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, ExprId),
+ ItemFn(P<FnDecl>, Unsafety, Constness, Abi, Generics, BodyId),
/// A module
ItemMod(Mod),
/// An external module
/// A union definition, e.g. `union Foo<A, B> {x: A, y: B}`
ItemUnion(VariantData, Generics),
/// Represents a Trait Declaration
- ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItem>),
+ ItemTrait(Unsafety, Generics, TyParamBounds, HirVec<TraitItemRef>),
// Default trait implementations
///
}
}
+/// A reference from an trait to one of its associated items. This
+/// contains the item's id, naturally, but also the item's name and
+/// some other high-level details (like whether it is an associated
+/// type or method, and whether it is public). This allows other
+/// passes to find the impl they want without loading the id (which
+/// means fewer edges in the incremental compilation graph).
+#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
+pub struct TraitItemRef {
+ pub id: TraitItemId,
+ pub name: Name,
+ pub kind: AssociatedItemKind,
+ pub span: Span,
+ pub defaultness: Defaultness,
+}
+
/// A reference from an impl to one of its associated items. This
/// contains the item's id, naturally, but also the item's name and
/// some other high-level details (like whether it is an associated
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
pub enum ForeignItem_ {
/// A foreign function
- ForeignItemFn(P<FnDecl>, Generics),
+ ForeignItemFn(P<FnDecl>, HirVec<Spanned<Name>>, Generics),
/// A foreign static item (`static ext: u8`), with optional mutability
/// (the boolean is true when mutable)
ForeignItemStatic(P<Ty>, bool),
use syntax::abi::Abi;
use syntax::ast;
use syntax::codemap::{CodeMap, Spanned};
-use syntax::parse::token::{self, BinOpToken};
use syntax::parse::lexer::comments;
use syntax::print::pp::{self, break_offset, word, space, hardbreak};
use syntax::print::pp::{Breaks, eof};
use errors;
use hir;
-use hir::{Crate, PatKind, RegionTyParamBound, SelfKind, TraitTyParamBound, TraitBoundModifier};
+use hir::{PatKind, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
use std::io::{self, Write, Read};
NodePat(&'a hir::Pat),
}
+pub enum Nested {
+ Item(hir::ItemId),
+ TraitItem(hir::TraitItemId),
+ ImplItem(hir::ImplItemId),
+ Body(hir::BodyId),
+ BodyArgPat(hir::BodyId, usize)
+}
+
pub trait PpAnn {
+ fn nested(&self, _state: &mut State, _nested: Nested) -> io::Result<()> {
+ Ok(())
+ }
fn pre(&self, _state: &mut State, _node: AnnNode) -> io::Result<()> {
Ok(())
}
}
}
-#[derive(Copy, Clone)]
pub struct NoAnn;
-
impl PpAnn for NoAnn {}
+pub const NO_ANN: &'static PpAnn = &NoAnn;
+impl PpAnn for hir::Crate {
+ fn nested(&self, state: &mut State, nested: Nested) -> io::Result<()> {
+ match nested {
+ Nested::Item(id) => state.print_item(self.item(id.id)),
+ Nested::TraitItem(id) => state.print_trait_item(self.trait_item(id)),
+ Nested::ImplItem(id) => state.print_impl_item(self.impl_item(id)),
+ Nested::Body(id) => state.print_expr(&self.body(id).value),
+ Nested::BodyArgPat(id, i) => state.print_pat(&self.body(id).arguments[i].pat)
+ }
+ }
+}
pub struct State<'a> {
- krate: Option<&'a Crate>,
pub s: pp::Printer<'a>,
cm: Option<&'a CodeMap>,
comments: Option<Vec<comments::Comment>>,
}
}
-pub fn rust_printer<'a>(writer: Box<Write + 'a>, krate: Option<&'a Crate>) -> State<'a> {
- static NO_ANN: NoAnn = NoAnn;
- rust_printer_annotated(writer, &NO_ANN, krate)
-}
-
-pub fn rust_printer_annotated<'a>(writer: Box<Write + 'a>,
- ann: &'a PpAnn,
- krate: Option<&'a Crate>)
- -> State<'a> {
- State {
- krate: krate,
- s: pp::mk_printer(writer, default_columns),
- cm: None,
- comments: None,
- literals: None,
- cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
- cur_cmnt: 0,
- cur_lit: 0,
- },
- boxes: Vec::new(),
- ann: ann,
- }
-}
-
#[allow(non_upper_case_globals)]
pub const indent_unit: usize = 4;
is_expanded: bool)
-> io::Result<()> {
let mut s = State::new_from_input(cm, span_diagnostic, filename, input,
- out, ann, is_expanded, Some(krate));
+ out, ann, is_expanded);
// When printing the AST, we sometimes need to inject `#[no_std]` here.
// Since you can't compile the HIR, it's not necessary.
input: &mut Read,
out: Box<Write + 'a>,
ann: &'a PpAnn,
- is_expanded: bool,
- krate: Option<&'a Crate>)
+ is_expanded: bool)
-> State<'a> {
let (cmnts, lits) = comments::gather_comments_and_literals(span_diagnostic,
filename,
None
} else {
Some(lits)
- },
- krate)
+ })
}
pub fn new(cm: &'a CodeMap,
out: Box<Write + 'a>,
ann: &'a PpAnn,
comments: Option<Vec<comments::Comment>>,
- literals: Option<Vec<comments::Literal>>,
- krate: Option<&'a Crate>)
+ literals: Option<Vec<comments::Literal>>)
-> State<'a> {
State {
- krate: krate,
s: pp::mk_printer(out, default_columns),
cm: Some(cm),
comments: comments.clone(),
}
}
-pub fn to_string<F>(f: F) -> String
+pub fn to_string<F>(ann: &PpAnn, f: F) -> String
where F: FnOnce(&mut State) -> io::Result<()>
{
let mut wr = Vec::new();
{
- let mut printer = rust_printer(Box::new(&mut wr), None);
+ let mut printer = State {
+ s: pp::mk_printer(Box::new(&mut wr), default_columns),
+ cm: None,
+ comments: None,
+ literals: None,
+ cur_cmnt_and_lit: ast_pp::CurrentCommentAndLiteral {
+ cur_cmnt: 0,
+ cur_lit: 0,
+ },
+ boxes: Vec::new(),
+ ann: ann,
+ };
f(&mut printer).unwrap();
eof(&mut printer.s).unwrap();
}
String::from_utf8(wr).unwrap()
}
-pub fn binop_to_string(op: BinOpToken) -> &'static str {
- match op {
- token::Plus => "+",
- token::Minus => "-",
- token::Star => "*",
- token::Slash => "/",
- token::Percent => "%",
- token::Caret => "^",
- token::And => "&",
- token::Or => "|",
- token::Shl => "<<",
- token::Shr => ">>",
- }
-}
-
-pub fn ty_to_string(ty: &hir::Ty) -> String {
- to_string(|s| s.print_type(ty))
-}
-
-pub fn bounds_to_string(bounds: &[hir::TyParamBound]) -> String {
- to_string(|s| s.print_bounds("", bounds))
-}
-
-pub fn pat_to_string(pat: &hir::Pat) -> String {
- to_string(|s| s.print_pat(pat))
-}
-
-pub fn arm_to_string(arm: &hir::Arm) -> String {
- to_string(|s| s.print_arm(arm))
-}
-
-pub fn expr_to_string(e: &hir::Expr) -> String {
- to_string(|s| s.print_expr(e))
-}
-
-pub fn lifetime_to_string(e: &hir::Lifetime) -> String {
- to_string(|s| s.print_lifetime(e))
-}
-
-pub fn stmt_to_string(stmt: &hir::Stmt) -> String {
- to_string(|s| s.print_stmt(stmt))
-}
-
-pub fn item_to_string(i: &hir::Item) -> String {
- to_string(|s| s.print_item(i))
-}
-
-pub fn impl_item_to_string(i: &hir::ImplItem) -> String {
- to_string(|s| s.print_impl_item(i))
-}
-
-pub fn trait_item_to_string(i: &hir::TraitItem) -> String {
- to_string(|s| s.print_trait_item(i))
-}
-
-pub fn generics_to_string(generics: &hir::Generics) -> String {
- to_string(|s| s.print_generics(generics))
-}
-
-pub fn where_clause_to_string(i: &hir::WhereClause) -> String {
- to_string(|s| s.print_where_clause(i))
-}
-
-pub fn fn_block_to_string(p: &hir::FnDecl) -> String {
- to_string(|s| s.print_fn_block_args(p))
-}
-
-pub fn path_to_string(p: &hir::Path) -> String {
- to_string(|s| s.print_path(p, false))
-}
-
-pub fn qpath_to_string(p: &hir::QPath) -> String {
- to_string(|s| s.print_qpath(p, false))
-}
-
-pub fn name_to_string(name: ast::Name) -> String {
- to_string(|s| s.print_name(name))
-}
-
-pub fn fun_to_string(decl: &hir::FnDecl,
- unsafety: hir::Unsafety,
- constness: hir::Constness,
- name: ast::Name,
- generics: &hir::Generics)
- -> String {
- to_string(|s| {
- s.head("")?;
- s.print_fn(decl,
- unsafety,
- constness,
- Abi::Rust,
- Some(name),
- generics,
- &hir::Inherited)?;
- s.end()?; // Close the head box
- s.end() // Close the outer box
+pub fn visibility_qualified(vis: &hir::Visibility, w: &str) -> String {
+ to_string(NO_ANN, |s| {
+ s.print_visibility(vis)?;
+ word(&mut s.s, w)
})
}
-pub fn block_to_string(blk: &hir::Block) -> String {
- to_string(|s| {
- // containing cbox, will be closed by print-block at }
- s.cbox(indent_unit)?;
- // head-ibox, will be closed by print-block after {
- s.ibox(0)?;
- s.print_block(blk)
- })
-}
-
-pub fn variant_to_string(var: &hir::Variant) -> String {
- to_string(|s| s.print_variant(var))
-}
-
-pub fn arg_to_string(arg: &hir::Arg) -> String {
- to_string(|s| s.print_arg(arg, false))
-}
-
-pub fn visibility_qualified(vis: &hir::Visibility, s: &str) -> String {
- match *vis {
- hir::Public => format!("pub {}", s),
- hir::Visibility::Crate => format!("pub(crate) {}", s),
- hir::Visibility::Restricted { ref path, .. } => format!("pub({}) {}", path, s),
- hir::Inherited => s.to_string(),
- }
-}
-
fn needs_parentheses(expr: &hir::Expr) -> bool {
match expr.node {
hir::ExprAssign(..) |
pub fn print_mod(&mut self, _mod: &hir::Mod, attrs: &[ast::Attribute]) -> io::Result<()> {
self.print_inner_attributes(attrs)?;
- for item_id in &_mod.item_ids {
- self.print_item_id(item_id)?;
+ for &item_id in &_mod.item_ids {
+ self.ann.nested(self, Nested::Item(item_id))?;
}
Ok(())
}
hir::TyImplTrait(ref bounds) => {
self.print_bounds("impl ", &bounds[..])?;
}
- hir::TyArray(ref ty, ref v) => {
+ hir::TyArray(ref ty, v) => {
word(&mut self.s, "[")?;
self.print_type(&ty)?;
word(&mut self.s, "; ")?;
- self.print_expr(&v)?;
+ self.ann.nested(self, Nested::Body(v))?;
word(&mut self.s, "]")?;
}
- hir::TyTypeof(ref e) => {
+ hir::TyTypeof(e) => {
word(&mut self.s, "typeof(")?;
- self.print_expr(&e)?;
+ self.ann.nested(self, Nested::Body(e))?;
word(&mut self.s, ")")?;
}
hir::TyInfer => {
self.maybe_print_comment(item.span.lo)?;
self.print_outer_attributes(&item.attrs)?;
match item.node {
- hir::ForeignItemFn(ref decl, ref generics) => {
+ hir::ForeignItemFn(ref decl, ref arg_names, ref generics) => {
self.head("")?;
self.print_fn(decl,
hir::Unsafety::Normal,
Abi::Rust,
Some(item.name),
generics,
- &item.vis)?;
+ &item.vis,
+ arg_names,
+ None)?;
self.end()?; // end head-ibox
word(&mut self.s, ";")?;
self.end() // end the outer fn box
fn print_associated_const(&mut self,
name: ast::Name,
ty: &hir::Ty,
- default: Option<&hir::Expr>,
+ default: Option<hir::BodyId>,
vis: &hir::Visibility)
-> io::Result<()> {
word(&mut self.s, &visibility_qualified(vis, ""))?;
if let Some(expr) = default {
space(&mut self.s)?;
self.word_space("=")?;
- self.print_expr(expr)?;
+ self.ann.nested(self, Nested::Body(expr))?;
}
word(&mut self.s, ";")
}
word(&mut self.s, ";")
}
- pub fn print_item_id(&mut self, item_id: &hir::ItemId) -> io::Result<()> {
- if let Some(krate) = self.krate {
- // skip nested items if krate context was not provided
- let item = &krate.items[&item_id.id];
- self.print_item(item)
- } else {
- Ok(())
- }
- }
-
- pub fn print_expr_id(&mut self, expr_id: &hir::ExprId) -> io::Result<()> {
- if let Some(krate) = self.krate {
- let expr = &krate.exprs[expr_id];
- self.print_expr(expr)
- } else {
- Ok(())
- }
- }
-
/// Pretty-print an item
pub fn print_item(&mut self, item: &hir::Item) -> io::Result<()> {
self.hardbreak_if_not_bol()?;
self.end()?; // end inner head-block
self.end()?; // end outer head-block
}
- hir::ItemStatic(ref ty, m, ref expr) => {
+ hir::ItemStatic(ref ty, m, expr) => {
self.head(&visibility_qualified(&item.vis, "static"))?;
if m == hir::MutMutable {
self.word_space("mut")?;
self.end()?; // end the head-ibox
self.word_space("=")?;
- self.print_expr(&expr)?;
+ self.ann.nested(self, Nested::Body(expr))?;
word(&mut self.s, ";")?;
self.end()?; // end the outer cbox
}
- hir::ItemConst(ref ty, ref expr) => {
+ hir::ItemConst(ref ty, expr) => {
self.head(&visibility_qualified(&item.vis, "const"))?;
self.print_name(item.name)?;
self.word_space(":")?;
self.end()?; // end the head-ibox
self.word_space("=")?;
- self.print_expr(&expr)?;
+ self.ann.nested(self, Nested::Body(expr))?;
word(&mut self.s, ";")?;
self.end()?; // end the outer cbox
}
- hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, ref body) => {
+ hir::ItemFn(ref decl, unsafety, constness, abi, ref typarams, body) => {
self.head("")?;
self.print_fn(decl,
unsafety,
abi,
Some(item.name),
typarams,
- &item.vis)?;
+ &item.vis,
+ &[],
+ Some(body))?;
word(&mut self.s, " ")?;
self.end()?; // need to close a box
self.end()?; // need to close a box
- self.print_expr_id(body)?;
+ self.ann.nested(self, Nested::Body(body))?;
}
hir::ItemMod(ref _mod) => {
self.head(&visibility_qualified(&item.vis, "mod"))?;
self.bopen()?;
self.print_inner_attributes(&item.attrs)?;
for impl_item in impl_items {
- self.print_impl_item_ref(impl_item)?;
+ self.ann.nested(self, Nested::ImplItem(impl_item.id))?;
}
self.bclose(item.span)?;
}
word(&mut self.s, " ")?;
self.bopen()?;
for trait_item in trait_items {
- self.print_trait_item(trait_item)?;
+ self.ann.nested(self, Nested::TraitItem(trait_item.id))?;
}
self.bclose(item.span)?;
}
match *vis {
hir::Public => self.word_nbsp("pub"),
hir::Visibility::Crate => self.word_nbsp("pub(crate)"),
- hir::Visibility::Restricted { ref path, .. } =>
- self.word_nbsp(&format!("pub({})", path)),
+ hir::Visibility::Restricted { ref path, .. } => {
+ word(&mut self.s, "pub(")?;
+ self.print_path(path, false)?;
+ self.word_nbsp(")")
+ }
hir::Inherited => Ok(()),
}
}
self.head("")?;
let generics = hir::Generics::empty();
self.print_struct(&v.node.data, &generics, v.node.name, v.span, false)?;
- match v.node.disr_expr {
- Some(ref d) => {
- space(&mut self.s)?;
- self.word_space("=")?;
- self.print_expr(&d)
- }
- _ => Ok(()),
+ if let Some(d) = v.node.disr_expr {
+ space(&mut self.s)?;
+ self.word_space("=")?;
+ self.ann.nested(self, Nested::Body(d))?;
}
+ Ok(())
}
pub fn print_method_sig(&mut self,
name: ast::Name,
m: &hir::MethodSig,
- vis: &hir::Visibility)
+ vis: &hir::Visibility,
+ arg_names: &[Spanned<ast::Name>],
+ body_id: Option<hir::BodyId>)
-> io::Result<()> {
self.print_fn(&m.decl,
m.unsafety,
m.abi,
Some(name),
&m.generics,
- vis)
+ vis,
+ arg_names,
+ body_id)
}
pub fn print_trait_item(&mut self, ti: &hir::TraitItem) -> io::Result<()> {
self.maybe_print_comment(ti.span.lo)?;
self.print_outer_attributes(&ti.attrs)?;
match ti.node {
- hir::ConstTraitItem(ref ty, ref default) => {
- self.print_associated_const(ti.name,
- &ty,
- default.as_ref().map(|expr| &**expr),
- &hir::Inherited)?;
- }
- hir::MethodTraitItem(ref sig, ref body) => {
- if body.is_some() {
- self.head("")?;
- }
- self.print_method_sig(ti.name, sig, &hir::Inherited)?;
- if let Some(ref body) = *body {
- self.nbsp()?;
- self.end()?; // need to close a box
- self.end()?; // need to close a box
- self.print_expr_id(body)?;
- } else {
- word(&mut self.s, ";")?;
- }
+ hir::TraitItemKind::Const(ref ty, default) => {
+ self.print_associated_const(ti.name, &ty, default, &hir::Inherited)?;
}
- hir::TypeTraitItem(ref bounds, ref default) => {
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref arg_names)) => {
+ self.print_method_sig(ti.name, sig, &hir::Inherited, arg_names, None)?;
+ word(&mut self.s, ";")?;
+ }
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
+ self.head("")?;
+ self.print_method_sig(ti.name, sig, &hir::Inherited, &[], Some(body))?;
+ self.nbsp()?;
+ self.end()?; // need to close a box
+ self.end()?; // need to close a box
+ self.ann.nested(self, Nested::Body(body))?;
+ }
+ hir::TraitItemKind::Type(ref bounds, ref default) => {
self.print_associated_type(ti.name,
Some(bounds),
default.as_ref().map(|ty| &**ty))?;
self.ann.post(self, NodeSubItem(ti.id))
}
- pub fn print_impl_item_ref(&mut self, item_ref: &hir::ImplItemRef) -> io::Result<()> {
- if let Some(krate) = self.krate {
- // skip nested items if krate context was not provided
- let item = &krate.impl_item(item_ref.id);
- self.print_impl_item(item)
- } else {
- Ok(())
- }
- }
-
pub fn print_impl_item(&mut self, ii: &hir::ImplItem) -> io::Result<()> {
self.ann.pre(self, NodeSubItem(ii.id))?;
self.hardbreak_if_not_bol()?;
}
match ii.node {
- hir::ImplItemKind::Const(ref ty, ref expr) => {
- self.print_associated_const(ii.name, &ty, Some(&expr), &ii.vis)?;
+ hir::ImplItemKind::Const(ref ty, expr) => {
+ self.print_associated_const(ii.name, &ty, Some(expr), &ii.vis)?;
}
- hir::ImplItemKind::Method(ref sig, ref body) => {
+ hir::ImplItemKind::Method(ref sig, body) => {
self.head("")?;
- self.print_method_sig(ii.name, sig, &ii.vis)?;
+ self.print_method_sig(ii.name, sig, &ii.vis, &[], Some(body))?;
self.nbsp()?;
self.end()?; // need to close a box
self.end()?; // need to close a box
- self.print_expr_id(body)?;
+ self.ann.nested(self, Nested::Body(body))?;
}
hir::ImplItemKind::Type(ref ty) => {
self.print_associated_type(ii.name, None, Some(ty))?;
self.end()
}
- fn print_expr_repeat(&mut self, element: &hir::Expr, count: &hir::Expr) -> io::Result<()> {
+ fn print_expr_repeat(&mut self, element: &hir::Expr, count: hir::BodyId) -> io::Result<()> {
self.ibox(indent_unit)?;
word(&mut self.s, "[")?;
self.print_expr(element)?;
self.word_space(";")?;
- self.print_expr(count)?;
+ self.ann.nested(self, Nested::Body(count))?;
word(&mut self.s, "]")?;
self.end()
}
hir::ExprArray(ref exprs) => {
self.print_expr_vec(exprs)?;
}
- hir::ExprRepeat(ref element, ref count) => {
- self.print_expr_repeat(&element, &count)?;
+ hir::ExprRepeat(ref element, count) => {
+ self.print_expr_repeat(&element, count)?;
}
hir::ExprStruct(ref qpath, ref fields, ref wth) => {
self.print_expr_struct(qpath, &fields[..], wth)?;
}
self.bclose_(expr.span, indent_unit)?;
}
- hir::ExprClosure(capture_clause, ref decl, ref body, _fn_decl_span) => {
+ hir::ExprClosure(capture_clause, ref decl, body, _fn_decl_span) => {
self.print_capture_clause(capture_clause)?;
- self.print_fn_block_args(&decl)?;
+ self.print_closure_args(&decl, body)?;
space(&mut self.s)?;
// this is a bare expression
- self.print_expr_id(body)?;
+ self.ann.nested(self, Nested::Body(body))?;
self.end()?; // need to close a box
// a box will be closed by print_expr, but we didn't want an overall
}
self.end()
}
- hir::DeclItem(ref item) => {
- self.print_item_id(item)
+ hir::DeclItem(item) => {
+ self.ann.nested(self, Nested::Item(item))
}
}
}
self.print_expr(coll)
}
- fn print_path(&mut self,
- path: &hir::Path,
- colons_before_params: bool)
- -> io::Result<()> {
+ pub fn print_path(&mut self,
+ path: &hir::Path,
+ colons_before_params: bool)
+ -> io::Result<()> {
self.maybe_print_comment(path.span.lo)?;
- let mut first = !path.global;
- for segment in &path.segments {
- if first {
- first = false
- } else {
+ for (i, segment) in path.segments.iter().enumerate() {
+ if i > 0 {
word(&mut self.s, "::")?
}
-
- self.print_name(segment.name)?;
-
- self.print_path_parameters(&segment.parameters, colons_before_params)?;
+ if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" {
+ self.print_name(segment.name)?;
+ self.print_path_parameters(&segment.parameters, colons_before_params)?;
+ }
}
Ok(())
}
- fn print_qpath(&mut self,
- qpath: &hir::QPath,
- colons_before_params: bool)
- -> io::Result<()> {
+ pub fn print_qpath(&mut self,
+ qpath: &hir::QPath,
+ colons_before_params: bool)
+ -> io::Result<()> {
match *qpath {
hir::QPath::Resolved(None, ref path) => {
self.print_path(path, colons_before_params)
space(&mut self.s)?;
self.word_space("as")?;
- let mut first = !path.global;
- for segment in &path.segments[..path.segments.len() - 1] {
- if first {
- first = false
- } else {
+ for (i, segment) in path.segments[..path.segments.len() - 1].iter().enumerate() {
+ if i > 0 {
word(&mut self.s, "::")?
}
- self.print_name(segment.name)?;
- self.print_path_parameters(&segment.parameters, colons_before_params)?;
+ if segment.name != keywords::CrateRoot.name() && segment.name != "$crate" {
+ self.print_name(segment.name)?;
+ self.print_path_parameters(&segment.parameters, colons_before_params)?;
+ }
}
word(&mut self.s, ">")?;
self.end() // close enclosing cbox
}
- fn print_explicit_self(&mut self, explicit_self: &hir::ExplicitSelf) -> io::Result<()> {
- match explicit_self.node {
- SelfKind::Value(m) => {
- self.print_mutability(m)?;
- word(&mut self.s, "self")
- }
- SelfKind::Region(ref lt, m) => {
- word(&mut self.s, "&")?;
- self.print_opt_lifetime(lt)?;
- self.print_mutability(m)?;
- word(&mut self.s, "self")
- }
- SelfKind::Explicit(ref typ, m) => {
- self.print_mutability(m)?;
- word(&mut self.s, "self")?;
- self.word_space(":")?;
- self.print_type(&typ)
- }
- }
- }
-
pub fn print_fn(&mut self,
decl: &hir::FnDecl,
unsafety: hir::Unsafety,
abi: Abi,
name: Option<ast::Name>,
generics: &hir::Generics,
- vis: &hir::Visibility)
+ vis: &hir::Visibility,
+ arg_names: &[Spanned<ast::Name>],
+ body_id: Option<hir::BodyId>)
-> io::Result<()> {
self.print_fn_header_info(unsafety, constness, abi, vis)?;
self.print_name(name)?;
}
self.print_generics(generics)?;
- self.print_fn_args_and_ret(decl)?;
- self.print_where_clause(&generics.where_clause)
- }
- pub fn print_fn_args_and_ret(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
self.popen()?;
- self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, false))?;
+ let mut i = 0;
+ // Make sure we aren't supplied *both* `arg_names` and `body_id`.
+ assert!(arg_names.is_empty() || body_id.is_none());
+ self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+ s.ibox(indent_unit)?;
+ if let Some(name) = arg_names.get(i) {
+ word(&mut s.s, &name.node.as_str())?;
+ word(&mut s.s, ":")?;
+ space(&mut s.s)?;
+ } else if let Some(body_id) = body_id {
+ s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
+ word(&mut s.s, ":")?;
+ space(&mut s.s)?;
+ }
+ i += 1;
+ s.print_type(ty)?;
+ s.end()
+ })?;
if decl.variadic {
word(&mut self.s, ", ...")?;
}
self.pclose()?;
- self.print_fn_output(decl)
+ self.print_fn_output(decl)?;
+ self.print_where_clause(&generics.where_clause)
}
- pub fn print_fn_block_args(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
+ fn print_closure_args(&mut self, decl: &hir::FnDecl, body_id: hir::BodyId) -> io::Result<()> {
word(&mut self.s, "|")?;
- self.commasep(Inconsistent, &decl.inputs, |s, arg| s.print_arg(arg, true))?;
+ let mut i = 0;
+ self.commasep(Inconsistent, &decl.inputs, |s, ty| {
+ s.ibox(indent_unit)?;
+
+ s.ann.nested(s, Nested::BodyArgPat(body_id, i))?;
+ i += 1;
+
+ if ty.node != hir::TyInfer {
+ word(&mut s.s, ":")?;
+ space(&mut s.s)?;
+ s.print_type(ty)?;
+ }
+ s.end()
+ })?;
word(&mut self.s, "|")?;
if let hir::DefaultReturn(..) = decl.output {
self.print_type(&mt.ty)
}
- pub fn print_arg(&mut self, input: &hir::Arg, is_closure: bool) -> io::Result<()> {
- self.ibox(indent_unit)?;
- match input.ty.node {
- hir::TyInfer if is_closure => self.print_pat(&input.pat)?,
- _ => {
- if let Some(eself) = input.to_self() {
- self.print_explicit_self(&eself)?;
- } else {
- let invalid = if let PatKind::Binding(_, _, name, _) = input.pat.node {
- name.node == keywords::Invalid.name()
- } else {
- false
- };
- if !invalid {
- self.print_pat(&input.pat)?;
- word(&mut self.s, ":")?;
- space(&mut self.s)?;
- }
- self.print_type(&input.ty)?;
- }
- }
- }
- self.end()
- }
-
pub fn print_fn_output(&mut self, decl: &hir::FnDecl) -> io::Result<()> {
if let hir::DefaultReturn(..) = decl.output {
return Ok(());
abi,
name,
&generics,
- &hir::Inherited)?;
+ &hir::Inherited,
+ &[],
+ None)?;
self.end()
}
use hir::map as ast_map;
use hir;
-use hir::print as pprust;
use lint;
use hir::def::Def;
Some(ref node) => match *node {
ast_map::NodeItem(ref item) => {
match item.node {
- hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, _) => {
- Some((fn_decl, gen, unsafety, constness, item.name, item.span))
+ hir::ItemFn(ref fn_decl, unsafety, constness, _, ref gen, body) => {
+ Some((fn_decl, gen, unsafety, constness, item.name, item.span, body))
}
_ => None,
}
return;
}
}
- if let hir::ImplItemKind::Method(ref sig, _) = item.node {
+ if let hir::ImplItemKind::Method(ref sig, body) = item.node {
Some((&sig.decl,
&sig.generics,
sig.unsafety,
sig.constness,
item.name,
- item.span))
+ item.span,
+ body))
} else {
None
}
},
ast_map::NodeTraitItem(item) => {
match item.node {
- hir::MethodTraitItem(ref sig, Some(_)) => {
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
Some((&sig.decl,
&sig.generics,
sig.unsafety,
sig.constness,
item.name,
- item.span))
+ item.span,
+ body))
}
_ => None,
}
},
None => None,
};
- let (fn_decl, generics, unsafety, constness, name, span)
+ let (fn_decl, generics, unsafety, constness, name, span, body)
= node_inner.expect("expect item fn");
let rebuilder = Rebuilder::new(self.tcx, fn_decl, generics, same_regions, &life_giver);
let (fn_decl, generics) = rebuilder.rebuild();
self.give_expl_lifetime_param(
- err, &fn_decl, unsafety, constness, name, &generics, span);
+ err, &fn_decl, unsafety, constness, name, &generics, span, body);
}
pub fn issue_32330_warnings(&self, span: Span, issue32330s: &[ty::Issue32330]) {
}
fn rebuild_args_ty(&self,
- inputs: &[hir::Arg],
+ inputs: &[P<hir::Ty>],
lifetime: hir::Lifetime,
anon_nums: &HashSet<u32>,
region_names: &HashSet<ast::Name>)
- -> hir::HirVec<hir::Arg> {
- let mut new_inputs = Vec::new();
- for arg in inputs {
- let new_ty = self.rebuild_arg_ty_or_output(&arg.ty, lifetime,
- anon_nums, region_names);
- let possibly_new_arg = hir::Arg {
- ty: new_ty,
- pat: arg.pat.clone(),
- id: arg.id
- };
- new_inputs.push(possibly_new_arg);
- }
- new_inputs.into()
+ -> hir::HirVec<P<hir::Ty>> {
+ inputs.iter().map(|arg_ty| {
+ self.rebuild_arg_ty_or_output(arg_ty, lifetime, anon_nums, region_names)
+ }).collect()
}
fn rebuild_output(&self, ty: &hir::FunctionRetTy,
new_segs.push(new_seg);
hir::Path {
span: path.span,
- global: path.global,
def: path.def,
segments: new_segs.into()
}
constness: hir::Constness,
name: ast::Name,
generics: &hir::Generics,
- span: Span) {
- let suggested_fn = pprust::fun_to_string(decl, unsafety, constness, name, generics);
- let msg = format!("consider using an explicit lifetime \
- parameter as shown: {}", suggested_fn);
+ span: Span,
+ body: hir::BodyId) {
+ let s = hir::print::to_string(&self.tcx.map, |s| {
+ use syntax::abi::Abi;
+ use syntax::print::pprust::PrintState;
+
+ s.head("")?;
+ s.print_fn(decl,
+ unsafety,
+ constness,
+ Abi::Rust,
+ Some(name),
+ generics,
+ &hir::Inherited,
+ &[],
+ Some(body))?;
+ s.end()?; // Close the head box
+ s.end() // Close the outer box
+ });
+ let msg = format!("consider using an explicit lifetime parameter as shown: {}", s);
err.span_help(span, &msg[..]);
}
#![feature(conservative_impl_trait)]
#![feature(const_fn)]
#![feature(core_intrinsics)]
-#![cfg_attr(stage0, feature(item_like_imports))]
#![feature(libc)]
#![feature(nonzero)]
+#![feature(pub_restricted)]
#![feature(quote)]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
pub mod middle {
pub mod astconv_util;
- pub mod expr_use_visitor; // STAGE0: increase glitch immunity
+ pub mod expr_use_visitor;
pub mod const_val;
- pub mod const_qualif;
pub mod cstore;
pub mod dataflow;
pub mod dead;
self.with_lint_attrs(&e.attrs, |cx| {
run_lints!(cx, check_expr, late_passes, e);
hir_visit::walk_expr(cx, e);
+ run_lints!(cx, check_expr_post, late_passes, e);
})
}
}
fn visit_fn(&mut self, fk: hir_visit::FnKind<'tcx>, decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId, span: Span, id: ast::NodeId) {
- let body = self.tcx.map.expr(body_id);
+ body_id: hir::BodyId, span: Span, id: ast::NodeId) {
+ let body = self.tcx.map.body(body_id);
run_lints!(self, check_fn, late_passes, fk, decl, body, span, id);
hir_visit::walk_fn(self, fk, decl, body_id, span, id);
run_lints!(self, check_fn_post, late_passes, fk, decl, body, span, id);
hir_visit::walk_decl(self, d);
}
- fn visit_expr_post(&mut self, e: &'tcx hir::Expr) {
- run_lints!(self, check_expr_post, late_passes, e);
- }
-
fn visit_generics(&mut self, g: &'tcx hir::Generics) {
run_lints!(self, check_generics, late_passes, g);
hir_visit::walk_generics(self, g);
_: &LateContext<'a, 'tcx>,
_: FnKind<'tcx>,
_: &'tcx hir::FnDecl,
- _: &'tcx hir::Expr,
+ _: &'tcx hir::Body,
_: Span,
_: ast::NodeId) { }
fn check_fn_post(&mut self,
_: &LateContext<'a, 'tcx>,
_: FnKind<'tcx>,
_: &'tcx hir::FnDecl,
- _: &'tcx hir::Expr,
+ _: &'tcx hir::Body,
_: Span,
_: ast::NodeId) { }
fn check_trait_item(&mut self, _: &LateContext<'a, 'tcx>, _: &'tcx hir::TraitItem) { }
+++ /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 qualification, from partial to completely promotable.
-bitflags! {
- #[derive(RustcEncodable, RustcDecodable)]
- flags ConstQualif: u8 {
- // Inner mutability (can not be placed behind a reference) or behind
- // &mut in a non-global expression. Can be copied from static memory.
- const MUTABLE_MEM = 1 << 0,
- // Constant value with a type that implements Drop. Can be copied
- // from static memory, similar to MUTABLE_MEM.
- const NEEDS_DROP = 1 << 1,
- // Even if the value can be placed in static memory, copying it from
- // there is more expensive than in-place instantiation, and/or it may
- // be too large. This applies to [T; N] and everything containing it.
- // N.B.: references need to clear this flag to not end up on the stack.
- const PREFER_IN_PLACE = 1 << 2,
- // May use more than 0 bytes of memory, doesn't impact the constness
- // directly, but is not allowed to be borrowed mutably in a constant.
- const NON_ZERO_SIZED = 1 << 3,
- // Actually borrowed, has to always be in static memory. Does not
- // propagate, and requires the expression to behave like a 'static
- // lvalue. The set of expressions with this flag is the minimum
- // that have to be promoted.
- const HAS_STATIC_BORROWS = 1 << 4,
- // Invalid const for miscellaneous reasons (e.g. not implemented).
- const NOT_CONST = 1 << 5,
-
- // Borrowing the expression won't produce &'static T if any of these
- // bits are set, though the value could be copied from static memory
- // if `NOT_CONST` isn't set.
- const NON_STATIC_BORROWS = ConstQualif::MUTABLE_MEM.bits |
- ConstQualif::NEEDS_DROP.bits |
- ConstQualif::NOT_CONST.bits
- }
-}
use session::Session;
use session::search_paths::PathKind;
use util::nodemap::{NodeSet, DefIdMap};
+
+use std::collections::BTreeMap;
use std::path::PathBuf;
use std::rc::Rc;
use syntax::ast;
use syntax::attr;
use syntax::ext::base::SyntaxExtension;
-use syntax::ptr::P;
use syntax::symbol::Symbol;
use syntax_pos::Span;
use rustc_back::target::Target;
use hir;
-use hir::intravisit::Visitor;
use rustc_back::PanicStrategy;
pub use self::NativeLibraryKind::{NativeStatic, NativeFramework, NativeUnknown};
pub foreign_items: Vec<DefIndex>,
}
-/// The data we save and restore about an inlined item or method. This is not
-/// part of the AST that we parse from a file, but it becomes part of the tree
-/// that we trans.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)]
-pub struct InlinedItem {
- pub def_id: DefId,
- pub body: P<hir::Expr>,
- pub const_fn_args: Vec<Option<DefId>>,
-}
-
-/// A borrowed version of `hir::InlinedItem`. This is what's encoded when saving
-/// a crate; it then gets read as an InlinedItem.
-#[derive(Clone, PartialEq, Eq, RustcEncodable, Hash, Debug)]
-pub struct InlinedItemRef<'a> {
- pub def_id: DefId,
- pub body: &'a hir::Expr,
- pub const_fn_args: Vec<Option<DefId>>,
-}
-
-fn get_fn_args(decl: &hir::FnDecl) -> Vec<Option<DefId>> {
- decl.inputs.iter().map(|arg| match arg.pat.node {
- hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
- _ => None
- }).collect()
-}
-
-impl<'a> InlinedItemRef<'a> {
- pub fn from_item<'b, 'tcx>(def_id: DefId,
- item: &'a hir::Item,
- tcx: TyCtxt<'b, 'a, 'tcx>)
- -> InlinedItemRef<'a> {
- let (body, args) = match item.node {
- hir::ItemFn(ref decl, _, _, _, _, body_id) =>
- (tcx.map.expr(body_id), get_fn_args(decl)),
- hir::ItemConst(_, ref body) => (&**body, Vec::new()),
- _ => bug!("InlinedItemRef::from_item wrong kind")
- };
- InlinedItemRef {
- def_id: def_id,
- body: body,
- const_fn_args: args
- }
- }
-
- pub fn from_trait_item(def_id: DefId,
- item: &'a hir::TraitItem,
- _tcx: TyCtxt)
- -> InlinedItemRef<'a> {
- let (body, args) = match item.node {
- hir::ConstTraitItem(_, Some(ref body)) =>
- (&**body, Vec::new()),
- hir::ConstTraitItem(_, None) => {
- bug!("InlinedItemRef::from_trait_item called for const without body")
- },
- _ => bug!("InlinedItemRef::from_trait_item wrong kind")
- };
- InlinedItemRef {
- def_id: def_id,
- body: body,
- const_fn_args: args
- }
- }
-
- pub fn from_impl_item<'b, 'tcx>(def_id: DefId,
- item: &'a hir::ImplItem,
- tcx: TyCtxt<'b, 'a, 'tcx>)
- -> InlinedItemRef<'a> {
- let (body, args) = match item.node {
- hir::ImplItemKind::Method(ref sig, body_id) =>
- (tcx.map.expr(body_id), get_fn_args(&sig.decl)),
- hir::ImplItemKind::Const(_, ref body) =>
- (&**body, Vec::new()),
- _ => bug!("InlinedItemRef::from_impl_item wrong kind")
- };
- InlinedItemRef {
- def_id: def_id,
- body: body,
- const_fn_args: args
- }
- }
-
- pub fn visit<V>(&self, visitor: &mut V)
- where V: Visitor<'a>
- {
- visitor.visit_expr(&self.body);
- }
-}
-
-impl InlinedItem {
- pub fn visit<'ast,V>(&'ast self, visitor: &mut V)
- where V: Visitor<'ast>
- {
- visitor.visit_expr(&self.body);
- }
-}
-
pub enum LoadedMacro {
MacroRules(ast::MacroDef),
ProcMacro(Rc<SyntaxExtension>),
// trait/impl-item info
fn trait_of_item(&self, def_id: DefId) -> Option<DefId>;
- fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<ty::AssociatedItem>;
+ fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>;
// flags
fn is_const_fn(&self, did: DefId) -> bool;
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro;
// misc. metadata
- fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<(&'tcx InlinedItem, ast::NodeId)>;
- fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId>;
- fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId>;
+ 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;
// trait/impl-item info
fn trait_of_item(&self, def_id: DefId) -> Option<DefId> { bug!("trait_of_item") }
- fn associated_item<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<ty::AssociatedItem> { bug!("associated_item") }
+ fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem> { bug!("associated_item") }
// flags
fn is_const_fn(&self, did: DefId) -> bool { bug!("is_const_fn") }
fn load_macro(&self, did: DefId, sess: &Session) -> LoadedMacro { bug!("load_macro") }
// misc. metadata
- fn maybe_get_item_ast<'a>(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<(&'tcx InlinedItem, ast::NodeId)> {
- bug!("maybe_get_item_ast")
+ 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 local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
- bug!("local_node_for_inlined_defid")
+ fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
+ bug!("item_body_nested_bodies")
}
- fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
- bug!("defid_for_inlined_node")
+ fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
+ bug!("const_is_rvalue_promotable_to_static")
}
fn get_item_mir<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
}
impl<'a, 'tcx, O:DataFlowOperator> pprust::PpAnn for DataFlowContext<'a, 'tcx, O> {
+ fn nested(&self, state: &mut pprust::State, nested: pprust::Nested) -> io::Result<()> {
+ pprust::PpAnn::nested(&self.tcx.map, state, nested)
+ }
fn pre(&self,
ps: &mut pprust::State,
node: pprust::AnnNode) -> io::Result<()> {
}
}
-fn build_nodeid_to_index(decl: Option<&hir::FnDecl>,
+fn build_nodeid_to_index(body: Option<&hir::Body>,
cfg: &cfg::CFG) -> NodeMap<Vec<CFGIndex>> {
let mut index = NodeMap();
// into cfg itself? i.e. introduce a fn-based flow-graph in
// addition to the current block-based flow-graph, rather than
// have to put traversals like this here?
- if let Some(decl) = decl {
- add_entries_from_fn_decl(&mut index, decl, cfg.entry);
+ if let Some(body) = body {
+ add_entries_from_fn_body(&mut index, body, cfg.entry);
}
cfg.graph.each_node(|node_idx, node| {
return index;
- fn add_entries_from_fn_decl(index: &mut NodeMap<Vec<CFGIndex>>,
- decl: &hir::FnDecl,
+ /// Add mappings from the ast nodes for the formal bindings to
+ /// the entry-node in the graph.
+ fn add_entries_from_fn_body(index: &mut NodeMap<Vec<CFGIndex>>,
+ body: &hir::Body,
entry: CFGIndex) {
- //! add mappings from the ast nodes for the formal bindings to
- //! the entry-node in the graph.
+ use hir::intravisit::Visitor;
+
struct Formals<'a> {
entry: CFGIndex,
index: &'a mut NodeMap<Vec<CFGIndex>>,
}
let mut formals = Formals { entry: entry, index: index };
- intravisit::walk_fn_decl(&mut formals, decl);
- impl<'a, 'v> intravisit::Visitor<'v> for Formals<'a> {
+ for arg in &body.arguments {
+ formals.visit_pat(&arg.pat);
+ }
+ impl<'a, 'v> Visitor<'v> for Formals<'a> {
fn nested_visit_map<'this>(&'this mut self) -> intravisit::NestedVisitorMap<'this, 'v> {
- panic!("should not encounter fn bodies or items")
+ intravisit::NestedVisitorMap::None
}
fn visit_pat(&mut self, p: &hir::Pat) {
impl<'a, 'tcx, O:DataFlowOperator> DataFlowContext<'a, 'tcx, O> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
analysis_name: &'static str,
- decl: Option<&hir::FnDecl>,
+ body: Option<&hir::Body>,
cfg: &cfg::CFG,
oper: O,
id_range: IdRange,
let kills2 = zeroes;
let on_entry = vec![entry; num_nodes * words_per_id];
- let nodeid_to_index = build_nodeid_to_index(decl, cfg);
+ let nodeid_to_index = build_nodeid_to_index(body, cfg);
DataFlowContext {
tcx: tcx,
impl<'a, 'tcx, O:DataFlowOperator+Clone+'static> DataFlowContext<'a, 'tcx, O> {
// ^^^^^^^^^^^^^ only needed for pretty printing
- pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Expr) {
+ pub fn propagate(&mut self, cfg: &cfg::CFG, body: &hir::Body) {
//! Performs the data flow analysis.
if self.bits_per_id == 0 {
}
debug!("Dataflow result for {}:", self.analysis_name);
- debug!("{}", {
- let mut v = Vec::new();
- self.pretty_print_to(box &mut v, body).unwrap();
- String::from_utf8(v).unwrap()
- });
- }
-
- fn pretty_print_to<'b>(&self, wr: Box<io::Write + 'b>,
- body: &hir::Expr) -> io::Result<()> {
- let mut ps = pprust::rust_printer_annotated(wr, self, None);
- ps.cbox(pprust::indent_unit)?;
- ps.ibox(0)?;
- ps.print_expr(body)?;
- pp::eof(&mut ps.s)
+ debug!("{}", pprust::to_string(self, |s| {
+ s.cbox(pprust::indent_unit)?;
+ s.ibox(0)?;
+ s.print_expr(&body.value)
+ }));
}
}
self.worklist.extend(enum_def.variants.iter()
.map(|variant| variant.node.data.id()));
}
- hir::ItemTrait(.., ref trait_items) => {
- for trait_item in trait_items {
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ for trait_item_ref in trait_item_refs {
+ let trait_item = self.krate.trait_item(trait_item_ref.id);
match trait_item.node {
- hir::ConstTraitItem(_, Some(_)) |
- hir::MethodTraitItem(_, Some(_)) => {
+ hir::TraitItemKind::Const(_, Some(_)) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => {
if has_allow_dead_code_or_lang_attr(&trait_item.attrs) {
self.worklist.push(trait_item.id);
}
}
}
+ fn visit_trait_item(&mut self, _item: &hir::TraitItem) {
+ // ignore: we are handling this in `visit_item` above
+ }
+
fn visit_impl_item(&mut self, _item: &hir::ImplItem) {
// ignore: we are handling this in `visit_item` above
}
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
match impl_item.node {
- hir::ImplItemKind::Const(_, ref expr) => {
+ hir::ImplItemKind::Const(_, body_id) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
impl_item.name, "associated const");
}
- intravisit::walk_expr(self, expr)
+ self.visit_nested_body(body_id)
}
hir::ImplItemKind::Method(_, body_id) => {
if !self.symbol_is_live(impl_item.id, None) {
self.warn_dead_code(impl_item.id, impl_item.span,
impl_item.name, "method");
}
- self.visit_body(body_id)
+ self.visit_nested_body(body_id)
}
hir::ImplItemKind::Type(..) => {}
}
// Overwrite so that we don't warn the trait item itself.
fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
match trait_item.node {
- hir::ConstTraitItem(_, Some(ref body)) => {
- intravisit::walk_expr(self, body)
- }
- hir::MethodTraitItem(_, Some(body_id)) => {
- self.visit_body(body_id)
+ hir::TraitItemKind::Const(_, Some(body_id)) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
+ self.visit_nested_body(body_id)
}
- hir::ConstTraitItem(_, None) |
- hir::MethodTraitItem(_, None) |
- hir::TypeTraitItem(..) => {}
+ hir::TraitItemKind::Const(_, None) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+ hir::TraitItemKind::Type(..) => {}
}
}
}
fn calculate_type(sess: &session::Session,
ty: config::CrateType) -> DependencyList {
+ if !sess.opts.output_types.should_trans() {
+ return Vec::new();
+ }
+
match ty {
// If the global prefer_dynamic switch is turned off, first attempt
// static linkage (this can fail).
// No linkage happens with rlibs, we just needed the metadata (which we
// got long ago), so don't bother with anything.
- config::CrateTypeRlib | config::CrateTypeMetadata => return Vec::new(),
+ config::CrateTypeRlib => return Vec::new(),
// Staticlibs and cdylibs must have all static dependencies. If any fail
// to be found, we generate some nice pretty errors.
}
fn visit_fn(&mut self, fn_kind: FnKind<'tcx>, fn_decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId, span: Span, id: ast::NodeId) {
+ body_id: hir::BodyId, span: Span, id: ast::NodeId) {
let (is_item_fn, is_unsafe_fn) = match fn_kind {
FnKind::ItemFn(_, _, unsafety, ..) =>
use syntax::attr;
use syntax::entry::EntryPointType;
use syntax_pos::Span;
-use hir::{Item, ItemFn, ImplItem};
+use hir::{Item, ItemFn, ImplItem, TraitItem};
use hir::itemlikevisit::ItemLikeVisitor;
struct EntryContext<'a, 'tcx: 'a> {
find_item(item, self, at_root);
}
+ fn visit_trait_item(&mut self, _trait_item: &'tcx TraitItem) {
+ // entry fn is never a trait item
+ }
fn visit_impl_item(&mut self, _impl_item: &'tcx ImplItem) {
// entry fn is never an impl item
}
}
- pub fn walk_fn(&mut self,
- decl: &hir::FnDecl,
- body: &hir::Expr) {
- self.walk_arg_patterns(decl, body);
- self.consume_expr(body);
- }
-
- fn walk_arg_patterns(&mut self,
- decl: &hir::FnDecl,
- body: &hir::Expr) {
- for arg in &decl.inputs {
+ pub fn consume_body(&mut self, body: &hir::Body) {
+ for arg in &body.arguments {
let arg_ty = return_if_err!(self.mc.infcx.node_ty(arg.pat.id));
- let fn_body_scope_r = self.tcx().node_scope_region(body.id);
+ let fn_body_scope_r = self.tcx().node_scope_region(body.value.id);
let arg_cmt = self.mc.cat_rvalue(
arg.id,
arg.pat.span,
self.walk_irrefutable_pat(arg_cmt, &arg.pat);
}
+
+ self.consume_expr(&body.value);
}
fn tcx(&self) -> TyCtxt<'a, 'gcx, 'tcx> {
}
}
- hir::ExprRepeat(ref base, ref count) => {
+ hir::ExprRepeat(ref base, _) => {
self.consume_expr(&base);
- self.consume_expr(&count);
}
hir::ExprClosure(.., fn_decl_span) => {
}
impl<'a, 'tcx> ItemVisitor<'a, 'tcx> {
- fn visit_const(&mut self, item_id: ast::NodeId, expr: &'tcx hir::Expr) {
+ fn visit_const(&mut self, item_id: ast::NodeId, body: hir::BodyId) {
let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
self.tcx.infer_ctxt(None, Some(param_env), Reveal::All).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
- visitor.visit_expr(expr);
+ visitor.visit_nested_body(body);
});
}
}
}
// const, static and N in [T; N].
- fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
+ fn visit_body(&mut self, body: &'tcx hir::Body) {
self.tcx.infer_ctxt(None, None, Reveal::All).enter(|infcx| {
let mut visitor = ExprVisitor {
infcx: &infcx
};
- visitor.visit_expr(expr);
+ visitor.visit_body(body);
});
}
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
- if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
- self.visit_const(item.id, expr);
+ if let hir::TraitItemKind::Const(_, Some(body)) = item.node {
+ self.visit_const(item.id, body);
} else {
intravisit::walk_trait_item(self, item);
}
}
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
- if let hir::ImplItemKind::Const(_, ref expr) = item.node {
- self.visit_const(item.id, expr);
+ if let hir::ImplItemKind::Const(_, body) = item.node {
+ self.visit_const(item.id, body);
} else {
intravisit::walk_impl_item(self, item);
}
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, id: ast::NodeId) {
+ b: hir::BodyId, s: Span, id: ast::NodeId) {
if let FnKind::Closure(..) = fk {
span_bug!(s, "intrinsicck: closure outside of function")
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ // at present, lang items are always items, not trait items
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
// at present, lang items are always items, not impl items
}
PanicFmtLangItem, "panic_fmt", panic_fmt;
ExchangeMallocFnLangItem, "exchange_malloc", exchange_malloc_fn;
- ExchangeFreeFnLangItem, "exchange_free", exchange_free_fn;
BoxFreeFnLangItem, "box_free", box_free_fn;
StrDupUniqFnLangItem, "strdup_uniq", strdup_uniq_fn;
use hir::Expr;
use hir;
-use hir::print::{expr_to_string, block_to_string};
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
/// For use with `propagate_through_loop`.
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, id: NodeId) {
+ b: hir::BodyId, s: Span, id: NodeId) {
visit_fn(self, fk, fd, b, s, id);
}
fn visit_local(&mut self, l: &'tcx hir::Local) { visit_local(self, l); }
impl<'a, 'tcx> Visitor<'tcx> for Liveness<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::OnlyBodies(&self.ir.tcx.map)
+ NestedVisitorMap::None
}
- fn visit_fn(&mut self, _: FnKind<'tcx>, _: &'tcx hir::FnDecl,
- _: hir::ExprId, _: Span, _: NodeId) {
- // do not check contents of nested fns
- }
fn visit_local(&mut self, l: &'tcx hir::Local) {
check_local(self, l);
}
fn visit_fn<'a, 'tcx: 'a>(ir: &mut IrMaps<'a, 'tcx>,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
sp: Span,
id: ast::NodeId) {
debug!("visit_fn");
debug!("creating fn_maps: {:?}", &fn_maps as *const IrMaps);
- for arg in &decl.inputs {
+ let body = ir.tcx.map.body(body_id);
+
+ for arg in &body.arguments {
arg.pat.each_binding(|_bm, arg_id, _x, path1| {
debug!("adding argument {}", arg_id);
let name = path1.node;
clean_exit_var: fn_maps.add_variable(CleanExit)
};
- let body = ir.tcx.map.expr(body_id);
-
// compute liveness
let mut lsets = Liveness::new(&mut fn_maps, specials);
- let entry_ln = lsets.compute(body);
+ let entry_ln = lsets.compute(&body.value);
// check for various error conditions
- lsets.visit_expr(body);
+ lsets.visit_body(body);
lsets.check_ret(id, sp, fk, entry_ln, body);
- lsets.warn_about_unused_args(decl, entry_ln);
+ lsets.warn_about_unused_args(body, entry_ln);
}
fn visit_local<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, local: &'tcx hir::Local) {
// effectively a return---this only occurs in `for` loops,
// where the body is really a closure.
- debug!("compute: using id for body, {}", expr_to_string(body));
+ debug!("compute: using id for body, {}", self.ir.tcx.map.node_to_pretty_string(body.id));
let exit_ln = self.s.exit_ln;
let entry_ln: LiveNode = self.with_loop_nodes(body.id, exit_ln, exit_ln, |this| {
fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
-> LiveNode {
- debug!("propagate_through_expr: {}", expr_to_string(expr));
+ debug!("propagate_through_expr: {}", self.ir.tcx.map.node_to_pretty_string(expr.id));
match expr.node {
// Interesting cases with control flow or which gen/kill
hir::ExprClosure(.., blk_id, _) => {
debug!("{} is an ExprClosure",
- expr_to_string(expr));
+ self.ir.tcx.map.node_to_pretty_string(expr.id));
/*
The next-node for a break is the successor of the entire
loop. The next-node for a continue is the top of this loop.
*/
let node = self.live_node(expr.id, expr.span);
- self.with_loop_nodes(blk_id.node_id(), succ, node, |this| {
+ self.with_loop_nodes(blk_id.node_id, succ, node, |this| {
// the construction of a closure itself is not important,
// but we have to consider the closed over variables.
self.propagate_through_exprs(exprs, succ)
}
- hir::ExprRepeat(ref element, ref count) => {
- let succ = self.propagate_through_expr(&count, succ);
- self.propagate_through_expr(&element, succ)
- }
-
hir::ExprStruct(_, ref fields, ref with_expr) => {
let succ = self.propagate_through_opt_expr(with_expr.as_ref().map(|e| &**e), succ);
fields.iter().rev().fold(succ, |succ, field| {
hir::ExprAddrOf(_, ref e) |
hir::ExprCast(ref e, _) |
hir::ExprType(ref e, _) |
- hir::ExprUnary(_, ref e) => {
+ hir::ExprUnary(_, ref e) |
+ hir::ExprRepeat(ref e, _) => {
self.propagate_through_expr(&e, succ)
}
}
}
debug!("propagate_through_loop: using id for loop body {} {}",
- expr.id, block_to_string(body));
+ expr.id, self.ir.tcx.map.node_to_pretty_string(body.id));
let cond_ln = match kind {
LoopLoop => ln,
sp: Span,
fk: FnKind,
entry_ln: LiveNode,
- body: &hir::Expr)
+ body: &hir::Body)
{
let fn_ty = if let FnKind::Closure(_) = fk {
self.ir.tcx.tables().node_id_to_type(id)
// and must outlive the *call-site* of the function.
let fn_ret =
self.ir.tcx.liberate_late_bound_regions(
- self.ir.tcx.region_maps.call_site_extent(id, body.id),
+ self.ir.tcx.region_maps.call_site_extent(id, body.value.id),
&fn_ret);
if !fn_ret.is_never() && self.live_on_entry(entry_ln, self.s.no_ret_var).is_some() {
}
}
- fn warn_about_unused_args(&self, decl: &hir::FnDecl, entry_ln: LiveNode) {
- for arg in &decl.inputs {
+ fn warn_about_unused_args(&self, body: &hir::Body, entry_ln: LiveNode) {
+ for arg in &body.arguments {
arg.pat.each_binding(|_bm, p_id, sp, path1| {
let var = self.variable(p_id, sp);
// Ignore unused self.
use hir::def_id::DefId;
use hir::map as ast_map;
use infer::InferCtxt;
-use middle::const_qualif::ConstQualif;
use hir::def::{Def, CtorKind};
use ty::adjustment;
use ty::{self, Ty, TyCtxt};
};
match fn_expr.node {
- hir::ExprClosure(.., body_id, _) => body_id.node_id(),
+ hir::ExprClosure(.., body_id, _) => body_id.node_id,
_ => bug!()
}
};
span: Span,
expr_ty: Ty<'tcx>)
-> cmt<'tcx> {
- let qualif = self.tcx().const_qualif_map.borrow().get(&id).cloned()
- .unwrap_or(ConstQualif::NOT_CONST);
+ let promotable = self.tcx().rvalue_promotable_to_static.borrow().get(&id).cloned()
+ .unwrap_or(false);
// Only promote `[T; 0]` before an RFC for rvalue promotions
// is accepted.
- let qualif = match expr_ty.sty {
- ty::TyArray(_, 0) => qualif,
- _ => ConstQualif::NOT_CONST
+ let promotable = match expr_ty.sty {
+ ty::TyArray(_, 0) => true,
+ _ => promotable & false
};
// Compute maximum lifetime of this rvalue. This is 'static if
// we can promote to a constant, otherwise equal to enclosing temp
// lifetime.
- let re = if qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
- self.temporary_scope(id)
- } else {
+ let re = if promotable {
self.tcx().mk_region(ty::ReStatic)
+ } else {
+ self.temporary_scope(id)
};
let ret = self.cat_rvalue(id, span, re, expr_ty);
debug!("cat_rvalue_node ret {:?}", ret);
fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ReachableContext<'a, 'tcx> {
let any_library = tcx.sess.crate_types.borrow().iter().any(|ty| {
*ty == config::CrateTypeRlib || *ty == config::CrateTypeDylib ||
- *ty == config::CrateTypeProcMacro || *ty == config::CrateTypeMetadata
+ *ty == config::CrateTypeProcMacro
});
ReachableContext {
tcx: tcx,
}
Some(ast_map::NodeTraitItem(trait_method)) => {
match trait_method.node {
- hir::ConstTraitItem(_, ref default) => default.is_some(),
- hir::MethodTraitItem(_, ref body) => body.is_some(),
- hir::TypeTraitItem(..) => false,
+ hir::TraitItemKind::Const(_, ref default) => default.is_some(),
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(_)) => true,
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+ hir::TraitItemKind::Type(..) => false,
}
}
Some(ast_map::NodeImplItem(impl_item)) => {
match item.node {
hir::ItemFn(.., body) => {
if item_might_be_inlined(&item) {
- self.visit_body(body);
+ self.visit_nested_body(body);
}
}
// Reachable constants will be inlined into other crates
// unconditionally, so we need to make sure that their
// contents are also reachable.
- hir::ItemConst(_, ref init) => {
- self.visit_expr(&init);
+ hir::ItemConst(_, init) => {
+ self.visit_nested_body(init);
}
// These are normal, nothing reachable about these
}
ast_map::NodeTraitItem(trait_method) => {
match trait_method.node {
- hir::ConstTraitItem(_, None) |
- hir::MethodTraitItem(_, None) => {
+ hir::TraitItemKind::Const(_, None) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) => {
// Keep going, nothing to get exported
}
- hir::ConstTraitItem(_, Some(ref body)) => {
- self.visit_expr(body);
+ hir::TraitItemKind::Const(_, Some(body_id)) |
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Provided(body_id)) => {
+ self.visit_nested_body(body_id);
}
- hir::MethodTraitItem(_, Some(body_id)) => {
- self.visit_body(body_id);
- }
- hir::TypeTraitItem(..) => {}
+ hir::TraitItemKind::Type(..) => {}
}
}
ast_map::NodeImplItem(impl_item) => {
match impl_item.node {
- hir::ImplItemKind::Const(_, ref expr) => {
- self.visit_expr(&expr);
+ hir::ImplItemKind::Const(_, body) => {
+ self.visit_nested_body(body);
}
hir::ImplItemKind::Method(ref sig, body) => {
let did = self.tcx.map.get_parent_did(search_item);
if method_might_be_inlined(self.tcx, sig, impl_item, did) {
- self.visit_body(body)
+ self.visit_nested_body(body)
}
}
hir::ImplItemKind::Type(_) => {}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {}
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
// processed in visit_item above
}
fn resolve_fn<'a, 'tcx>(visitor: &mut RegionResolutionVisitor<'tcx, 'a>,
kind: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
sp: Span,
id: ast::NodeId) {
debug!("region::resolve_fn(id={:?}, \
visitor.cx.parent);
visitor.cx.parent = visitor.new_code_extent(
- CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
+ CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
let fn_decl_scope = visitor.new_code_extent(
- CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id() });
+ CodeExtentData::ParameterScope { fn_id: id, body_id: body_id.node_id });
if let Some(root_id) = visitor.cx.root_id {
- visitor.region_maps.record_fn_parent(body_id.node_id(), root_id);
+ visitor.region_maps.record_fn_parent(body_id.node_id, root_id);
}
let outer_cx = visitor.cx;
let outer_ts = mem::replace(&mut visitor.terminating_scopes, NodeSet());
- visitor.terminating_scopes.insert(body_id.node_id());
+ visitor.terminating_scopes.insert(body_id.node_id);
// The arguments and `self` are parented to the fn.
visitor.cx = Context {
- root_id: Some(body_id.node_id()),
+ root_id: Some(body_id.node_id),
parent: ROOT_CODE_EXTENT,
var_parent: fn_decl_scope,
};
// The body of the every fn is a root scope.
visitor.cx = Context {
- root_id: Some(body_id.node_id()),
+ root_id: Some(body_id.node_id),
parent: fn_decl_scope,
var_parent: fn_decl_scope
};
- visitor.visit_body(body_id);
+ visitor.visit_nested_body(body_id);
// Restore context we had at the start.
visitor.cx = outer_cx;
}
fn visit_fn(&mut self, fk: FnKind<'ast>, fd: &'ast FnDecl,
- b: hir::ExprId, s: Span, n: NodeId) {
+ b: hir::BodyId, s: Span, n: NodeId) {
resolve_fn(self, fk, fd, b, s, n);
}
fn visit_arm(&mut self, a: &'ast Arm) {
use rustc_data_structures::fx::FxHashSet;
use hir;
-use hir::print::lifetime_to_string;
use hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
#[derive(Clone, Copy, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable, Debug)]
// Items always introduce a new root scope
self.with(RootScope, |_, this| {
match item.node {
- hir::ForeignItemFn(ref decl, ref generics) => {
+ hir::ForeignItemFn(ref decl, _, ref generics) => {
this.visit_early_late(item.id, decl, generics, |this| {
intravisit::walk_foreign_item(this, item);
})
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, decl: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, fn_id: ast::NodeId) {
+ b: hir::BodyId, s: Span, fn_id: ast::NodeId) {
match fk {
FnKind::ItemFn(_, generics, ..) => {
self.visit_early_late(fn_id,decl, generics, |this| {
// methods in an impl can reuse label names.
let saved = replace(&mut self.labels_in_fn, vec![]);
- if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
+ if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) =
+ trait_item.node {
self.visit_early_late(
trait_item.id,
&sig.decl, &sig.generics,
// Adds all labels in `b` to `ctxt.labels_in_fn`, signalling a warning
// if one of the label shadows a lifetime or another label.
-fn extract_labels(ctxt: &mut LifetimeContext, b: hir::ExprId) {
+fn extract_labels(ctxt: &mut LifetimeContext, b: hir::BodyId) {
struct GatherLabels<'a> {
sess: &'a Session,
scope: Scope<'a>,
scope: ctxt.scope,
labels_in_fn: &mut ctxt.labels_in_fn,
};
- gather.visit_expr(ctxt.hir_map.expr(b));
+ gather.visit_body(ctxt.hir_map.body(b));
return;
impl<'v, 'a> Visitor<'v> for GatherLabels<'a> {
fn add_scope_and_walk_fn(&mut self,
fk: FnKind<'tcx>,
fd: &'tcx hir::FnDecl,
- fb: hir::ExprId,
+ fb: hir::BodyId,
_span: Span,
fn_id: ast::NodeId) {
match fk {
// `self.labels_in_fn`.
extract_labels(self, fb);
- self.with(FnScope { fn_id: fn_id, body_id: fb.node_id(), s: self.scope },
- |_old_scope, this| this.visit_body(fb))
+ self.with(FnScope { fn_id: fn_id, body_id: fb.node_id, s: self.scope },
+ |_old_scope, this| this.visit_nested_body(fb))
}
// FIXME(#37666) this works around a limitation in the region inferencer
probably a bug in syntax::fold");
}
- debug!("lifetime_ref={:?} id={:?} resolved to {:?} span={:?}",
- lifetime_to_string(lifetime_ref),
- lifetime_ref.id,
+ debug!("{} resolved to {:?} span={:?}",
+ self.hir_map.node_to_string(lifetime_ref.id),
def,
self.sess.codemap().span_to_string(lifetime_ref.span));
self.map.defs.insert(lifetime_ref.id, def);
debug!("insert_late_bound_lifetimes(decl={:?}, generics={:?})", decl, generics);
let mut constrained_by_input = ConstrainedCollector { regions: FxHashSet() };
- for arg in &decl.inputs {
- constrained_by_input.visit_ty(&arg.ty);
+ for arg_ty in &decl.inputs {
+ constrained_by_input.visit_ty(arg_ty);
}
let mut appears_in_output = AllCollector {
config::CrateTypeCdylib |
config::CrateTypeExecutable |
config::CrateTypeStaticlib => true,
- config::CrateTypeRlib |
- config::CrateTypeMetadata => false,
+ config::CrateTypeRlib => false,
}
});
if !needs_check {
match tcx.map.get(id) {
map::NodeItem(&Item { node: ItemConst(..), .. }) |
- map::NodeTraitItem(&TraitItem { node: ConstTraitItem(..), .. }) |
+ map::NodeTraitItem(&TraitItem { node: TraitItemKind::Const(..), .. }) |
map::NodeImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) => {
MirSource::Const(id)
}
Bitcode,
Assembly,
LlvmAssembly,
+ Metadata,
Object,
Exe,
DepInfo,
OutputType::Bitcode |
OutputType::Assembly |
OutputType::LlvmAssembly |
- OutputType::Object => false,
+ OutputType::Object |
+ OutputType::Metadata => false,
}
}
OutputType::Assembly => "asm",
OutputType::LlvmAssembly => "llvm-ir",
OutputType::Object => "obj",
+ OutputType::Metadata => "metadata",
OutputType::Exe => "link",
OutputType::DepInfo => "dep-info",
}
OutputType::Assembly => "s",
OutputType::LlvmAssembly => "ll",
OutputType::Object => "o",
+ OutputType::Metadata => "rmeta",
OutputType::DepInfo => "d",
OutputType::Exe => "",
}
pub fn values<'a>(&'a self) -> BTreeMapValuesIter<'a, OutputType, Option<PathBuf>> {
self.0.values()
}
+
+ // True if any of the output types require codegen or linking.
+ pub fn should_trans(&self) -> bool {
+ self.0.keys().any(|k| match *k {
+ OutputType::Bitcode |
+ OutputType::Assembly |
+ OutputType::LlvmAssembly |
+ OutputType::Object |
+ OutputType::Exe => true,
+ OutputType::Metadata |
+ OutputType::DepInfo => false,
+ })
+ }
}
CrateTypeStaticlib,
CrateTypeCdylib,
CrateTypeProcMacro,
- CrateTypeMetadata,
}
#[derive(Clone, Hash)]
let os = &sess.target.target.target_os;
let env = &sess.target.target.target_env;
let vendor = &sess.target.target.target_vendor;
+ let min_atomic_width = sess.target.target.min_atomic_width();
let max_atomic_width = sess.target.target.max_atomic_width();
- let fam = if let Some(ref fam) = sess.target.target.options.target_family {
- Symbol::intern(fam)
- } else if sess.target.target.options.is_like_windows {
- Symbol::intern("windows")
- } else {
- Symbol::intern("unix")
- };
-
let mut ret = HashSet::new();
// Target bindings.
ret.insert((Symbol::intern("target_os"), Some(Symbol::intern(os))));
- ret.insert((Symbol::intern("target_family"), Some(fam)));
+ if let Some(ref fam) = sess.target.target.options.target_family {
+ ret.insert((Symbol::intern("target_family"), Some(Symbol::intern(fam))));
+ if fam == "windows" || fam == "unix" {
+ ret.insert((Symbol::intern(fam), None));
+ }
+ }
ret.insert((Symbol::intern("target_arch"), Some(Symbol::intern(arch))));
ret.insert((Symbol::intern("target_endian"), Some(Symbol::intern(end))));
ret.insert((Symbol::intern("target_pointer_width"), Some(Symbol::intern(wordsz))));
ret.insert((Symbol::intern("target_env"), Some(Symbol::intern(env))));
ret.insert((Symbol::intern("target_vendor"), Some(Symbol::intern(vendor))));
- if fam == "windows" || fam == "unix" {
- ret.insert((fam, None));
- }
if sess.target.target.options.has_elf_tls {
ret.insert((Symbol::intern("target_thread_local"), None));
}
for &i in &[8, 16, 32, 64, 128] {
- if i <= max_atomic_width {
+ if i >= min_atomic_width && i <= max_atomic_width {
let s = i.to_string();
ret.insert((Symbol::intern("target_has_atomic"), Some(Symbol::intern(&s))));
if &s == wordsz {
assumed.", "[KIND=]NAME"),
opt::multi_s("", "crate-type", "Comma separated list of types of crates
for the compiler to emit",
- "[bin|lib|rlib|dylib|cdylib|staticlib|metadata]"),
+ "[bin|lib|rlib|dylib|cdylib|staticlib]"),
opt::opt_s("", "crate-name", "Specify the name of the crate being built",
"NAME"),
opt::multi_s("", "emit", "Comma separated list of types of output for \
the compiler to emit",
- "[asm|llvm-bc|llvm-ir|obj|link|dep-info]"),
+ "[asm|llvm-bc|llvm-ir|obj|metadata|link|dep-info]"),
opt::multi_s("", "print", "Comma separated list of compiler information to \
print on stdout", &print_opts.join("|")),
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
};
let unparsed_crate_types = matches.opt_strs("crate-type");
- let crate_types = parse_crate_types_from_list(unparsed_crate_types)
+ let (crate_types, emit_metadata) = parse_crate_types_from_list(unparsed_crate_types)
.unwrap_or_else(|e| early_error(error_format, &e[..]));
let mut lint_opts = vec![];
"llvm-ir" => OutputType::LlvmAssembly,
"llvm-bc" => OutputType::Bitcode,
"obj" => OutputType::Object,
+ "metadata" => OutputType::Metadata,
"link" => OutputType::Exe,
"dep-info" => OutputType::DepInfo,
part => {
}
}
};
- if output_types.is_empty() {
+ if emit_metadata {
+ output_types.insert(OutputType::Metadata, None);
+ } else if output_types.is_empty() {
output_types.insert(OutputType::Exe, None);
}
cfg)
}
-pub fn parse_crate_types_from_list(list_list: Vec<String>) -> Result<Vec<CrateType>, String> {
+pub fn parse_crate_types_from_list(list_list: Vec<String>)
+ -> Result<(Vec<CrateType>, bool), String> {
let mut crate_types: Vec<CrateType> = Vec::new();
+ let mut emit_metadata = false;
for unparsed_crate_type in &list_list {
for part in unparsed_crate_type.split(',') {
let new_part = match part {
"cdylib" => CrateTypeCdylib,
"bin" => CrateTypeExecutable,
"proc-macro" => CrateTypeProcMacro,
- "metadata" => CrateTypeMetadata,
+ // FIXME(#38640) remove this when Cargo is fixed.
+ "metadata" => {
+ early_warn(ErrorOutputType::default(), "--crate-type=metadata is deprecated, \
+ prefer --emit=metadata");
+ emit_metadata = true;
+ CrateTypeRlib
+ }
_ => {
return Err(format!("unknown crate type: `{}`",
part));
}
}
- return Ok(crate_types);
+ return Ok((crate_types, emit_metadata));
}
pub mod nightly_options {
CrateTypeStaticlib => "staticlib".fmt(f),
CrateTypeCdylib => "cdylib".fmt(f),
CrateTypeProcMacro => "proc-macro".fmt(f),
- CrateTypeMetadata => "metadata".fmt(f),
}
}
}
/// FIXME(arielb1): why is this separate from populated_external_types?
pub populated_external_primitive_impls: RefCell<DefIdSet>,
- /// Cache used by const_eval when decoding external constants.
- /// Contains `None` when the constant has been fetched but doesn't exist.
- /// Constains `Some(expr_id, type)` otherwise.
- /// `type` is `None` in case it's not a primitive type
- pub extern_const_statics: RefCell<DefIdMap<Option<(NodeId, Option<Ty<'tcx>>)>>>,
- /// Cache used by const_eval when decoding extern const fns
- pub extern_const_fns: RefCell<DefIdMap<NodeId>>,
-
/// Maps any item's def-id to its stability index.
pub stability: RefCell<stability::Index<'tcx>>,
/// Caches the representation hints for struct definitions.
repr_hint_cache: RefCell<DepTrackingMap<maps::ReprHints<'tcx>>>,
- /// Maps Expr NodeId's to their constant qualification.
- pub const_qualif_map: RefCell<NodeMap<middle::const_qualif::ConstQualif>>,
+ /// 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>>,
used_trait_imports: RefCell::new(NodeSet()),
populated_external_types: RefCell::new(DefIdSet()),
populated_external_primitive_impls: RefCell::new(DefIdSet()),
- extern_const_statics: RefCell::new(DefIdMap()),
- extern_const_fns: RefCell::new(DefIdMap()),
stability: RefCell::new(stability),
selection_cache: traits::SelectionCache::new(),
evaluation_cache: traits::EvaluationCache::new(),
repr_hint_cache: RefCell::new(DepTrackingMap::new(dep_graph.clone())),
- const_qualif_map: RefCell::new(NodeMap()),
+ rvalue_promotable_to_static: RefCell::new(NodeMap()),
custom_coerce_unsized_kinds: RefCell::new(DefIdMap()),
cast_kinds: RefCell::new(NodeMap()),
fragment_infos: RefCell::new(DefIdMap()),
});
}
+ // Disable field reordering until we can decide what to do.
+ // The odd pattern here avoids a warning about the value never being read.
+ if can_optimize { can_optimize = false }
+
let (optimize, sort_ascending) = match kind {
StructKind::AlwaysSizedUnivariant => (can_optimize, false),
StructKind::MaybeUnsizedUnivariant => (can_optimize, false),
/// Visible everywhere (including in other crates).
Public,
/// Visible only in the given crate-local module.
- Restricted(NodeId),
+ Restricted(DefId),
/// Not visible anywhere in the local crate. This is the visibility of private external items.
- PrivateExternal,
+ Invisible,
}
-pub trait NodeIdTree {
- fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool;
+pub trait DefIdTree: Copy {
+ fn parent(self, id: DefId) -> Option<DefId>;
}
-impl<'a> NodeIdTree for ast_map::Map<'a> {
- fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
- let mut node_ancestor = node;
- while node_ancestor != ancestor {
- let node_ancestor_parent = self.get_module_parent(node_ancestor);
- if node_ancestor_parent == node_ancestor {
- return false;
- }
- node_ancestor = node_ancestor_parent;
- }
- true
+impl<'a, 'gcx, 'tcx> DefIdTree for TyCtxt<'a, 'gcx, 'tcx> {
+ fn parent(self, id: DefId) -> Option<DefId> {
+ self.def_key(id).parent.map(|index| DefId { index: index, ..id })
}
}
pub fn from_hir(visibility: &hir::Visibility, id: NodeId, tcx: TyCtxt) -> Self {
match *visibility {
hir::Public => Visibility::Public,
- hir::Visibility::Crate => Visibility::Restricted(ast::CRATE_NODE_ID),
+ hir::Visibility::Crate => Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)),
hir::Visibility::Restricted { ref path, .. } => match path.def {
// If there is no resolution, `resolve` will have already reported an error, so
// assume that the visibility is public to avoid reporting more privacy errors.
Def::Err => Visibility::Public,
- def => Visibility::Restricted(tcx.map.as_local_node_id(def.def_id()).unwrap()),
+ def => Visibility::Restricted(def.def_id()),
},
- hir::Inherited => Visibility::Restricted(tcx.map.get_module_parent(id)),
+ hir::Inherited => {
+ Visibility::Restricted(tcx.map.local_def_id(tcx.map.get_module_parent(id)))
+ }
}
}
/// Returns true if an item with this visibility is accessible from the given block.
- pub fn is_accessible_from<T: NodeIdTree>(self, block: NodeId, tree: &T) -> bool {
+ pub fn is_accessible_from<T: DefIdTree>(self, mut module: DefId, tree: T) -> bool {
let restriction = match self {
// Public items are visible everywhere.
Visibility::Public => return true,
// Private items from other crates are visible nowhere.
- Visibility::PrivateExternal => return false,
+ Visibility::Invisible => return false,
// Restricted items are visible in an arbitrary local module.
+ Visibility::Restricted(other) if other.krate != module.krate => return false,
Visibility::Restricted(module) => module,
};
- tree.is_descendant_of(block, restriction)
+ while module != restriction {
+ match tree.parent(module) {
+ Some(parent) => module = parent,
+ None => return false,
+ }
+ }
+
+ true
}
/// Returns true if this visibility is at least as accessible as the given visibility
- pub fn is_at_least<T: NodeIdTree>(self, vis: Visibility, tree: &T) -> bool {
+ pub fn is_at_least<T: DefIdTree>(self, vis: Visibility, tree: T) -> bool {
let vis_restriction = match vis {
Visibility::Public => return self == Visibility::Public,
- Visibility::PrivateExternal => return true,
+ Visibility::Invisible => return true,
Visibility::Restricted(module) => module,
};
tcx.construct_parameter_environment(
impl_item.span,
tcx.map.local_def_id(id),
- tcx.region_maps.call_site_extent(id, body.node_id()))
+ tcx.region_maps.call_site_extent(id, body.node_id))
}
}
}
Some(ast_map::NodeTraitItem(trait_item)) => {
match trait_item.node {
- hir::TypeTraitItem(..) | hir::ConstTraitItem(..) => {
+ hir::TraitItemKind::Type(..) | hir::TraitItemKind::Const(..) => {
// associated types don't have their own entry (for some reason),
// so for now just grab environment for the trait
let trait_id = tcx.map.get_parent(id);
trait_def_id,
tcx.region_maps.item_extent(id))
}
- hir::MethodTraitItem(_, ref body) => {
+ hir::TraitItemKind::Method(_, ref body) => {
// Use call-site for extent (unless this is a
// trait method with no default; then fallback
// to the method id).
- let extent = if let Some(body_id) = *body {
+ let extent = if let hir::TraitMethod::Provided(body_id) = *body {
// default impl: use call_site extent as free_id_outlive bound.
- tcx.region_maps.call_site_extent(id, body_id.node_id())
+ tcx.region_maps.call_site_extent(id, body_id.node_id)
} else {
// no default impl: use item extent as free_id_outlive bound.
tcx.region_maps.item_extent(id)
tcx.construct_parameter_environment(
item.span,
fn_def_id,
- tcx.region_maps.call_site_extent(id, body_id.node_id()))
+ tcx.region_maps.call_site_extent(id, body_id.node_id))
}
hir::ItemEnum(..) |
hir::ItemStruct(..) |
tcx.construct_parameter_environment(
expr.span,
base_def_id,
- tcx.region_maps.call_site_extent(id, body.node_id()))
+ tcx.region_maps.call_site_extent(id, body.node_id))
} else {
tcx.empty_parameter_environment()
}
block: Option<NodeId>,
tcx: TyCtxt<'a, 'gcx, 'tcx>,
substs: &'tcx Substs<'tcx>) -> bool {
- block.map_or(true, |b| self.vis.is_accessible_from(b, &tcx.map)) &&
+ block.map_or(true, |b| tcx.vis_is_accessible_from(self.vis, b)) &&
self.ty(tcx, substs).is_uninhabited_recurse(visited, block, tcx)
}
}
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(self.global_tcx(), def_id)
+ return self.sess.cstore.associated_item(def_id)
.expect("missing AssociatedItem in metadata");
}
}
}
- hir::ItemTrait(.., ref trait_items) => {
- for trait_item in trait_items {
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ for trait_item_ref in trait_item_refs {
let assoc_item =
- self.associated_item_from_trait_item_ref(parent_def_id, trait_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);
}
}
fn associated_item_from_trait_item_ref(self,
parent_def_id: DefId,
- trait_item: &hir::TraitItem)
+ trait_item_ref: &hir::TraitItemRef)
-> AssociatedItem {
- let def_id = self.map.local_def_id(trait_item.id);
-
- let (kind, has_self, has_value) = match trait_item.node {
- hir::MethodTraitItem(ref sig, ref body) => {
- (AssociatedKind::Method, sig.decl.get_self().is_some(),
- body.is_some())
- }
- hir::ConstTraitItem(_, ref value) => {
- (AssociatedKind::Const, false, value.is_some())
- }
- hir::TypeTraitItem(_, ref ty) => {
- (AssociatedKind::Type, false, ty.is_some())
+ let def_id = self.map.local_def_id(trait_item_ref.id.node_id);
+ let (kind, has_self) = match trait_item_ref.kind {
+ hir::AssociatedItemKind::Const => (ty::AssociatedKind::Const, false),
+ hir::AssociatedItemKind::Method { has_self } => {
+ (ty::AssociatedKind::Method, has_self)
}
+ hir::AssociatedItemKind::Type => (ty::AssociatedKind::Type, false),
};
AssociatedItem {
- name: trait_item.name,
+ name: trait_item_ref.name,
kind: kind,
- vis: Visibility::from_hir(&hir::Inherited, trait_item.id, self),
- defaultness: hir::Defaultness::Default { has_value: has_value },
+ vis: Visibility::from_hir(&hir::Inherited, trait_item_ref.id.node_id, self),
+ defaultness: trait_item_ref.defaultness,
def_id: def_id,
container: TraitContainer(parent_def_id),
method_has_self_argument: has_self
let id = self.map.as_local_node_id(def_id).unwrap();
let item = self.map.expect_item(id);
let vec: Vec<_> = match item.node {
- hir::ItemTrait(.., ref trait_items) => {
- trait_items.iter()
- .map(|trait_item| trait_item.id)
- .map(|id| self.map.local_def_id(id))
- .collect()
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ trait_item_refs.iter()
+ .map(|trait_item_ref| trait_item_ref.id)
+ .map(|id| self.map.local_def_id(id.node_id))
+ .collect()
}
hir::ItemImpl(.., ref impl_item_refs) => {
impl_item_refs.iter()
}
}
+ pub fn vis_is_accessible_from(self, vis: Visibility, block: NodeId) -> bool {
+ vis.is_accessible_from(self.map.local_def_id(self.map.get_module_parent(block)), self)
+ }
+
pub fn item_name(self, id: DefId) -> ast::Name {
if let Some(id) = self.map.as_local_node_id(id) {
self.map.name(id)
/// 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(self.global_tcx(), def_id)
- .and_then(|item| {
+ return self.sess.cstore.associated_item(def_id).and_then(|item| {
match item.container {
TraitContainer(_) => None,
ImplContainer(def_id) => Some(def_id),
#[derive(Clone, Copy, Debug)]
pub struct ErrorReported;
+thread_local!(static TIME_DEPTH: Cell<usize> = Cell::new(0));
+
+/// Read the current depth of `time()` calls. This is used to
+/// encourage indentation across threads.
+pub fn time_depth() -> usize {
+ TIME_DEPTH.with(|slot| slot.get())
+}
+
+/// Set the current depth of `time()` calls. The idea is to call
+/// `set_time_depth()` with the result from `time_depth()` in the
+/// parent thread.
+pub fn set_time_depth(depth: usize) {
+ TIME_DEPTH.with(|slot| slot.set(depth));
+}
+
pub fn time<T, F>(do_it: bool, what: &str, f: F) -> T where
F: FnOnce() -> T,
{
- thread_local!(static DEPTH: Cell<usize> = Cell::new(0));
if !do_it { return f(); }
- let old = DEPTH.with(|slot| {
+ let old = TIME_DEPTH.with(|slot| {
let r = slot.get();
slot.set(r + 1);
r
mem_string,
what);
- DEPTH.with(|slot| slot.set(old));
+ TIME_DEPTH.with(|slot| slot.set(old));
rv
}
function_sections: false,
dynamic_linking: true,
executables: true,
+ target_family: Some("unix".to_string()),
is_like_osx: true,
has_rpath: true,
dll_prefix: "lib".to_string(),
obj_is_bitcode: true,
max_atomic_width: Some(32),
post_link_args: vec!["-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+ target_family: Some("unix".to_string()),
.. Default::default()
};
Ok(Target {
TargetOptions {
dynamic_linking: true,
executables: true,
+ target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
position_independent_executables: true,
TargetOptions {
dynamic_linking: true,
executables: true,
+ target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec![
TargetOptions {
dynamic_linking: true,
executables: true,
+ target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec![
TargetOptions {
dynamic_linking: true,
executables: true,
+ target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec![
dynamic_linking: true,
executables: true,
has_rpath: true,
+ target_family: Some("unix".to_string()),
linker_is_gnu: true,
.. Default::default()
}
TargetOptions {
dynamic_linking: true,
executables: true,
+ target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec![
mod windows_msvc_base;
mod thumb_base;
mod fuchsia_base;
+mod redox_base;
pub type TargetResult = Result<Target, String>;
("aarch64-unknown-fuchsia", aarch64_unknown_fuchsia),
("x86_64-unknown-fuchsia", x86_64_unknown_fuchsia),
+ ("x86_64-unknown-redox", x86_64_unknown_redox),
+
("i386-apple-ios", i386_apple_ios),
("x86_64-apple-ios", x86_64_apple_ios),
("aarch64-apple-ios", aarch64_apple_ios),
// file
pub no_integrated_as: bool,
+ /// Don't use this field; instead use the `.min_atomic_width()` method.
+ pub min_atomic_width: Option<u64>,
+
/// Don't use this field; instead use the `.max_atomic_width()` method.
pub max_atomic_width: Option<u64>,
has_elf_tls: false,
obj_is_bitcode: false,
no_integrated_as: false,
+ min_atomic_width: None,
max_atomic_width: None,
panic_strategy: PanicStrategy::Unwind,
abi_blacklist: vec![],
}
}
+ /// Minimum integer size in bits that this target can perform atomic
+ /// operations on.
+ pub fn min_atomic_width(&self) -> u64 {
+ self.options.min_atomic_width.unwrap_or(8)
+ }
+
/// Maximum integer size in bits that this target can perform atomic
/// operations on.
pub fn max_atomic_width(&self) -> u64 {
key!(obj_is_bitcode, bool);
key!(no_integrated_as, bool);
key!(max_atomic_width, Option<u64>);
+ key!(min_atomic_width, Option<u64>);
try!(key!(panic_strategy, PanicStrategy));
key!(crt_static_default, bool);
target_option_val!(has_elf_tls);
target_option_val!(obj_is_bitcode);
target_option_val!(no_integrated_as);
+ target_option_val!(min_atomic_width);
target_option_val!(max_atomic_width);
target_option_val!(panic_strategy);
target_option_val!(crt_static_default);
TargetOptions {
dynamic_linking: true,
executables: true,
+ target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
pre_link_args: vec![
TargetOptions {
dynamic_linking: true,
executables: true,
+ target_family: Some("unix".to_string()),
linker_is_gnu: true,
has_rpath: true,
is_like_openbsd: true,
--- /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 PanicStrategy;
+use target::TargetOptions;
+use std::default::Default;
+
+pub fn opts() -> TargetOptions {
+ TargetOptions {
+ pre_link_args: vec![
+ // We want to be able to strip as much executable code as possible
+ // from the linker command line, and this flag indicates to the
+ // linker that it can avoid linking in dynamic libraries that don't
+ // actually satisfy any symbols up to that point (as with many other
+ // resolutions the linker does). This option only applies to all
+ // following libraries so we're sure to pass it as one of the first
+ // arguments.
+ "-Wl,--as-needed".to_string(),
+
+ // Always enable NX protection when it is available
+ "-Wl,-z,noexecstack".to_string(),
+
+ // Static link
+ "-static".to_string()
+ ],
+ late_link_args: vec![
+ "-lc".to_string(),
+ "-lm".to_string()
+ ],
+ executables: true,
+ relocation_model: "static".to_string(),
+ disable_redzone: true,
+ eliminate_frame_pointer: false,
+ target_family: None,
+ linker_is_gnu: true,
+ no_default_libraries: true,
+ lib_allocation_crate: "alloc_system".to_string(),
+ exe_allocation_crate: "alloc_system".to_string(),
+ has_elf_tls: true,
+ panic_strategy: PanicStrategy::Abort,
+ .. Default::default()
+ }
+}
dynamic_linking: true,
executables: true,
has_rpath: true,
+ target_family: Some("unix".to_string()),
is_like_solaris: true,
exe_allocation_crate: super::maybe_jemalloc(),
max_atomic_width: Some(32),
post_link_args: vec!["-s".to_string(), "BINARYEN=1".to_string(),
"-s".to_string(), "ERROR_ON_UNDEFINED_SYMBOLS=1".to_string()],
+ target_family: Some("unix".to_string()),
.. Default::default()
};
Ok(Target {
staticlib_prefix: "".to_string(),
staticlib_suffix: ".lib".to_string(),
no_default_libraries: true,
+ target_family: Some("windows".to_string()),
is_like_windows: true,
allows_weak_linkage: false,
pre_link_args: vec![
exe_suffix: ".exe".to_string(),
staticlib_prefix: "".to_string(),
staticlib_suffix: ".lib".to_string(),
+ target_family: Some("windows".to_string()),
is_like_windows: true,
is_like_msvc: true,
pre_link_args: vec![
--- /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::redox_base::opts();
+ base.cpu = "x86-64".to_string();
+ base.max_atomic_width = Some(64);
+ base.pre_link_args.push("-m64".to_string());
+
+ Ok(Target {
+ llvm_target: "x86_64-unknown-redox".to_string(),
+ target_endian: "little".to_string(),
+ target_pointer_width: "64".to_string(),
+ data_layout: "e-m:e-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+ arch: "x86_64".to_string(),
+ target_os: "redox".to_string(),
+ target_env: "".to_string(),
+ target_vendor: "unknown".to_string(),
+ options: base,
+ })
+}
move_data: &move_data::FlowedMoveData<'c, 'tcx>,
all_loans: &[Loan<'tcx>],
fn_id: ast::NodeId,
- decl: &hir::FnDecl,
- body: &hir::Expr) {
- debug!("check_loans(body id={})", body.id);
+ body: &hir::Body) {
+ debug!("check_loans(body id={})", body.value.id);
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
all_loans: all_loans,
param_env: &infcx.parameter_environment
};
- euv::ExprUseVisitor::new(&mut clcx, &infcx).walk_fn(decl, body);
+ euv::ExprUseVisitor::new(&mut clcx, &infcx).consume_body(body);
}
#[derive(PartialEq)]
pub fn gather_loans_in_fn<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
fn_id: NodeId,
- decl: &hir::FnDecl,
- body: &hir::Expr)
+ body: &hir::Body)
-> (Vec<Loan<'tcx>>,
move_data::MoveData<'tcx>) {
let mut glcx = GatherLoanCtxt {
bccx: bccx,
all_loans: Vec::new(),
- item_ub: bccx.tcx.region_maps.node_extent(body.id),
+ item_ub: bccx.tcx.region_maps.node_extent(body.value.id),
move_data: MoveData::new(),
move_error_collector: move_error::MoveErrorCollector::new(),
};
let param_env = ty::ParameterEnvironment::for_item(bccx.tcx, fn_id);
let infcx = bccx.tcx.borrowck_fake_infer_ctxt(param_env);
- euv::ExprUseVisitor::new(&mut glcx, &infcx).walk_fn(decl, body);
+ euv::ExprUseVisitor::new(&mut glcx, &infcx).consume_body(body);
glcx.report_potential_errors();
let GatherLoanCtxt { all_loans, move_data, .. } = glcx;
pub fn gather_loans_in_static_initializer<'a, 'tcx>(bccx: &mut BorrowckCtxt<'a, 'tcx>,
item_id: ast::NodeId,
- expr: &'tcx hir::Expr) {
+ body: hir::BodyId) {
- debug!("gather_loans_in_static_initializer(expr={:?})", expr);
+ debug!("gather_loans_in_static_initializer(expr={:?})", body);
let mut sicx = StaticInitializerCtxt {
bccx: bccx,
item_id: item_id
};
- sicx.visit_expr(expr);
+ sicx.visit_nested_body(body);
}
use std::mem;
use std::path::Path;
-use super::super::MoveDataParamEnv;
use super::super::MirBorrowckCtxtPreDataflow;
use super::{BitDenotation, DataflowState};
impl<O: BitDenotation> DataflowState<O> {
- fn each_bit<F>(&self, ctxt: &O::Ctxt, words: &IdxSet<O::Idx>, mut f: F)
+ fn each_bit<F>(&self, words: &IdxSet<O::Idx>, mut f: F)
where F: FnMut(O::Idx) {
//! Helper for iterating over the bits in a bitvector.
- let bits_per_block = self.operator.bits_per_block(ctxt);
+ let bits_per_block = self.operator.bits_per_block();
let usize_bits: usize = mem::size_of::<usize>() * 8;
for (word_index, &word) in words.words().iter().enumerate() {
}
pub fn interpret_set<'c, P>(&self,
- ctxt: &'c O::Ctxt,
+ o: &'c O,
words: &IdxSet<O::Idx>,
render_idx: &P)
-> Vec<&'c Debug>
- where P: for <'b> Fn(&'b O::Ctxt, O::Idx) -> &'b Debug
+ where P: Fn(&O, O::Idx) -> &Debug
{
let mut v = Vec::new();
- self.each_bit(ctxt, words, |i| {
- v.push(render_idx(ctxt, i));
+ self.each_bit(words, |i| {
+ v.push(render_idx(o, i));
});
v
}
}
pub trait MirWithFlowState<'tcx> {
- type BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>;
+ type BD: BitDenotation;
fn node_id(&self) -> NodeId;
fn mir(&self) -> &Mir<'tcx>;
- fn analysis_ctxt(&self) -> &<Self::BD as BitDenotation>::Ctxt;
fn flow_state(&self) -> &DataflowState<Self::BD>;
}
impl<'a, 'tcx: 'a, BD> MirWithFlowState<'tcx> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
- where 'tcx: 'a, BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>
+ where 'tcx: 'a, BD: BitDenotation
{
type BD = BD;
fn node_id(&self) -> NodeId { self.node_id }
fn mir(&self) -> &Mir<'tcx> { self.flow_state.mir() }
- fn analysis_ctxt(&self) -> &BD::Ctxt { &self.flow_state.ctxt }
fn flow_state(&self) -> &DataflowState<Self::BD> { &self.flow_state.flow_state }
}
path: &Path,
render_idx: P)
-> io::Result<()>
- where BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>,
- P: for <'b> Fn(&'b BD::Ctxt, BD::Idx) -> &'b Debug
+ where BD: BitDenotation,
+ P: Fn(&BD, BD::Idx) -> &Debug
{
let g = Graph { mbcx: mbcx, phantom: PhantomData, render_idx: render_idx };
let mut v = Vec::new();
impl<'a, 'tcx, MWF, P> dot::Labeller<'a> for Graph<'a, 'tcx, MWF, P>
where MWF: MirWithFlowState<'tcx>,
- P: for <'b> Fn(&'b <MWF::BD as BitDenotation>::Ctxt,
- <MWF::BD as BitDenotation>::Idx)
- -> &'b Debug,
+ P: for <'b> Fn(&'b MWF::BD, <MWF::BD as BitDenotation>::Idx) -> &'b Debug,
{
type Node = Node;
type Edge = Edge;
::rustc_mir::graphviz::write_node_label(
*n, self.mbcx.mir(), &mut v, 4,
|w| {
- let ctxt = self.mbcx.analysis_ctxt();
let flow = self.mbcx.flow_state();
- let entry_interp = flow.interpret_set(ctxt,
+ let entry_interp = flow.interpret_set(&flow.operator,
flow.sets.on_entry_set_for(i),
&self.render_idx);
chunked_present_left(w, &entry_interp[..], chunk_size)?;
entrybits=bits_to_string(entry.words(), bits_per_block))
},
|w| {
- let ctxt = self.mbcx.analysis_ctxt();
let flow = self.mbcx.flow_state();
let gen_interp =
- flow.interpret_set(ctxt, flow.sets.gen_set_for(i), &self.render_idx);
+ flow.interpret_set(&flow.operator, flow.sets.gen_set_for(i), &self.render_idx);
let kill_interp =
- flow.interpret_set(ctxt, flow.sets.kill_set_for(i), &self.render_idx);
+ flow.interpret_set(&flow.operator, flow.sets.kill_set_for(i), &self.render_idx);
chunked_present_left(w, &gen_interp[..], chunk_size)?;
let bits_per_block = flow.sets.bits_per_block();
{
use rustc_data_structures::indexed_set::{IdxSet};
use rustc_data_structures::indexed_vec::Idx;
-use super::super::gather_moves::{MoveOutIndex, MovePathIndex};
+use super::super::gather_moves::{HasMoveData, MoveData, MoveOutIndex, MovePathIndex};
use super::super::MoveDataParamEnv;
use super::super::DropFlagState;
use super::super::drop_flag_effects_for_function_entry;
pub struct MaybeInitializedLvals<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>,
}
impl<'a, 'tcx: 'a> MaybeInitializedLvals<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
- MaybeInitializedLvals { tcx: tcx, mir: mir }
+ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>)
+ -> Self
+ {
+ MaybeInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
}
}
+impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeInitializedLvals<'a, 'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
+}
+
/// `MaybeUninitializedLvals` tracks all l-values that might be
/// uninitialized upon reaching a particular point in the control flow
/// for a function.
pub struct MaybeUninitializedLvals<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>,
}
impl<'a, 'tcx: 'a> MaybeUninitializedLvals<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
- MaybeUninitializedLvals { tcx: tcx, mir: mir }
+ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>)
+ -> Self
+ {
+ MaybeUninitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
}
}
+impl<'a, 'tcx: 'a> HasMoveData<'tcx> for MaybeUninitializedLvals<'a, 'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
+}
+
/// `DefinitelyInitializedLvals` tracks all l-values that are definitely
/// initialized upon reaching a particular point in the control flow
/// for a function.
pub struct DefinitelyInitializedLvals<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>,
}
impl<'a, 'tcx: 'a> DefinitelyInitializedLvals<'a, 'tcx> {
- pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, mir: &'a Mir<'tcx>) -> Self {
- DefinitelyInitializedLvals { tcx: tcx, mir: mir }
+ pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>)
+ -> Self
+ {
+ DefinitelyInitializedLvals { tcx: tcx, mir: mir, mdpe: mdpe }
}
}
+impl<'a, 'tcx: 'a> HasMoveData<'tcx> for DefinitelyInitializedLvals<'a, 'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
+}
+
/// `MovingOutStatements` tracks the statements that perform moves out
/// of particular l-values. More precisely, it tracks whether the
/// *effect* of such moves (namely, the uninitialization of the
pub struct MovingOutStatements<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
+ mdpe: &'a MoveDataParamEnv<'tcx>,
+}
+
+impl<'a, 'tcx> HasMoveData<'tcx> for MovingOutStatements<'a, 'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx> { &self.mdpe.move_data }
}
impl<'a, 'tcx> MaybeInitializedLvals<'a, 'tcx> {
impl<'a, 'tcx> BitDenotation for MaybeInitializedLvals<'a, 'tcx> {
type Idx = MovePathIndex;
- type Ctxt = MoveDataParamEnv<'tcx>;
fn name() -> &'static str { "maybe_init" }
- fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
- ctxt.move_data.move_paths.len()
+ fn bits_per_block(&self) -> usize {
+ self.move_data().move_paths.len()
}
- fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<MovePathIndex>)
+ fn start_block_effect(&self, sets: &mut BlockSets<MovePathIndex>)
{
drop_flag_effects_for_function_entry(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
|path, s| {
assert!(s == DropFlagState::Present);
sets.on_entry.add(&path);
}
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
idx: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: idx },
|path, s| Self::update_bits(sets, path, s)
)
}
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
statements_len: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: statements_len },
|path, s| Self::update_bits(sets, path, s)
)
}
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<MovePathIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_lval: &mir::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
- on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
- ctxt.move_data.rev_lookup.find(dest_lval),
+ on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
+ self.move_data().rev_lookup.find(dest_lval),
|mpi| { in_out.add(&mpi); });
}
}
impl<'a, 'tcx> BitDenotation for MaybeUninitializedLvals<'a, 'tcx> {
type Idx = MovePathIndex;
- type Ctxt = MoveDataParamEnv<'tcx>;
fn name() -> &'static str { "maybe_uninit" }
- fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
- ctxt.move_data.move_paths.len()
+ fn bits_per_block(&self) -> usize {
+ self.move_data().move_paths.len()
}
// sets on_entry bits for Arg lvalues
- fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<MovePathIndex>) {
+ fn start_block_effect(&self, sets: &mut BlockSets<MovePathIndex>) {
// set all bits to 1 (uninit) before gathering counterevidence
for e in sets.on_entry.words_mut() { *e = !0; }
drop_flag_effects_for_function_entry(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
|path, s| {
assert!(s == DropFlagState::Present);
sets.on_entry.remove(&path);
}
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
idx: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: idx },
|path, s| Self::update_bits(sets, path, s)
)
}
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
statements_len: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: statements_len },
|path, s| Self::update_bits(sets, path, s)
)
}
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<MovePathIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_lval: &mir::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 0 (initialized).
- on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
- ctxt.move_data.rev_lookup.find(dest_lval),
+ on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
+ self.move_data().rev_lookup.find(dest_lval),
|mpi| { in_out.remove(&mpi); });
}
}
impl<'a, 'tcx> BitDenotation for DefinitelyInitializedLvals<'a, 'tcx> {
type Idx = MovePathIndex;
- type Ctxt = MoveDataParamEnv<'tcx>;
fn name() -> &'static str { "definite_init" }
- fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
- ctxt.move_data.move_paths.len()
+ fn bits_per_block(&self) -> usize {
+ self.move_data().move_paths.len()
}
// sets on_entry bits for Arg lvalues
- fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<MovePathIndex>) {
+ fn start_block_effect(&self, sets: &mut BlockSets<MovePathIndex>) {
for e in sets.on_entry.words_mut() { *e = 0; }
drop_flag_effects_for_function_entry(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
|path, s| {
assert!(s == DropFlagState::Present);
sets.on_entry.add(&path);
}
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
idx: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: idx },
|path, s| Self::update_bits(sets, path, s)
)
}
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MovePathIndex>,
bb: mir::BasicBlock,
statements_len: usize)
{
drop_flag_effects_for_location(
- self.tcx, self.mir, ctxt,
+ self.tcx, self.mir, self.mdpe,
Location { block: bb, statement_index: statements_len },
|path, s| Self::update_bits(sets, path, s)
)
}
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<MovePathIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_lval: &mir::Lvalue) {
// when a call returns successfully, that means we need to set
// the bits for that dest_lval to 1 (initialized).
- on_lookup_result_bits(self.tcx, self.mir, &ctxt.move_data,
- ctxt.move_data.rev_lookup.find(dest_lval),
+ on_lookup_result_bits(self.tcx, self.mir, self.move_data(),
+ self.move_data().rev_lookup.find(dest_lval),
|mpi| { in_out.add(&mpi); });
}
}
impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
type Idx = MoveOutIndex;
- type Ctxt = MoveDataParamEnv<'tcx>;
fn name() -> &'static str { "moving_out" }
- fn bits_per_block(&self, ctxt: &Self::Ctxt) -> usize {
- ctxt.move_data.moves.len()
+ fn bits_per_block(&self) -> usize {
+ self.move_data().moves.len()
}
- fn start_block_effect(&self,_move_data: &Self::Ctxt, _sets: &mut BlockSets<MoveOutIndex>) {
+ fn start_block_effect(&self, _sets: &mut BlockSets<MoveOutIndex>) {
// no move-statements have been executed prior to function
// execution, so this method has no effect on `_sets`.
}
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MoveOutIndex>,
bb: mir::BasicBlock,
idx: usize) {
- let (tcx, mir, move_data) = (self.tcx, self.mir, &ctxt.move_data);
+ let (tcx, mir, move_data) = (self.tcx, self.mir, self.move_data());
let stmt = &mir[bb].statements[idx];
let loc_map = &move_data.loc_map;
let path_map = &move_data.path_map;
// here, in dataflow vector
zero_to_one(sets.gen_set.words_mut(), *move_index);
}
- let bits_per_block = self.bits_per_block(ctxt);
+ let bits_per_block = self.bits_per_block();
match stmt.kind {
mir::StatementKind::SetDiscriminant { .. } => {
span_bug!(stmt.source_info.span, "SetDiscriminant should not exist in borrowck");
}
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<MoveOutIndex>,
bb: mir::BasicBlock,
statements_len: usize)
{
- let (mir, move_data) = (self.mir, &ctxt.move_data);
+ let (mir, move_data) = (self.mir, self.move_data());
let term = mir[bb].terminator();
let loc_map = &move_data.loc_map;
let loc = Location { block: bb, statement_index: statements_len };
debug!("terminator {:?} at loc {:?} moves out of move_indexes {:?}",
term, loc, &loc_map[loc]);
- let bits_per_block = self.bits_per_block(ctxt);
+ let bits_per_block = self.bits_per_block();
for move_index in &loc_map[loc] {
assert!(move_index.index() < bits_per_block);
zero_to_one(sets.gen_set.words_mut(), *move_index);
}
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<MoveOutIndex>,
_call_bb: mir::BasicBlock,
_dest_bb: mir::BasicBlock,
dest_lval: &mir::Lvalue) {
- let move_data = &ctxt.move_data;
- let bits_per_block = self.bits_per_block(ctxt);
+ let move_data = self.move_data();
+ let bits_per_block = self.bits_per_block();
let path_map = &move_data.path_map;
on_lookup_result_bits(self.tcx,
use std::usize;
use super::MirBorrowckCtxtPreDataflow;
-use super::MoveDataParamEnv;
pub use self::sanity_check::sanity_check_via_rustc_peek;
pub use self::impls::{MaybeInitializedLvals, MaybeUninitializedLvals};
mod impls;
pub trait Dataflow<BD: BitDenotation> {
- fn dataflow<P>(&mut self, p: P) where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug;
+ fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug;
}
impl<'a, 'tcx: 'a, BD> Dataflow<BD> for MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
- where BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>> + DataflowOperator
+ where BD: BitDenotation + DataflowOperator
{
- fn dataflow<P>(&mut self, p: P) where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug {
+ fn dataflow<P>(&mut self, p: P) where P: Fn(&BD, BD::Idx) -> &Debug {
self.flow_state.build_sets();
self.pre_dataflow_instrumentation(|c,i| p(c,i)).unwrap();
self.flow_state.propagate();
}
struct PropagationContext<'b, 'a: 'b, 'tcx: 'a, O>
- where O: 'b + BitDenotation, O::Ctxt: 'a
+ where O: 'b + BitDenotation
{
builder: &'b mut DataflowAnalysis<'a, 'tcx, O>,
changed: bool,
{
let sets = &mut self.flow_state.sets.for_block(mir::START_BLOCK.index());
- self.flow_state.operator.start_block_effect(&self.ctxt, sets);
+ self.flow_state.operator.start_block_effect(sets);
}
for (bb, data) in self.mir.basic_blocks().iter_enumerated() {
let sets = &mut self.flow_state.sets.for_block(bb.index());
for j_stmt in 0..statements.len() {
- self.flow_state.operator.statement_effect(&self.ctxt, sets, bb, j_stmt);
+ self.flow_state.operator.statement_effect(sets, bb, j_stmt);
}
if terminator.is_some() {
let stmts_len = statements.len();
- self.flow_state.operator.terminator_effect(&self.ctxt, sets, bb, stmts_len);
+ self.flow_state.operator.terminator_effect(sets, bb, stmts_len);
}
}
}
}
impl<'a, 'tcx: 'a, BD> MirBorrowckCtxtPreDataflow<'a, 'tcx, BD>
- where BD: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>>
+ where BD: BitDenotation
{
fn pre_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
- where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug
+ where P: Fn(&BD, BD::Idx) -> &Debug
{
if let Some(ref path_str) = self.print_preflow_to {
let path = dataflow_path(BD::name(), "preflow", path_str);
}
fn post_dataflow_instrumentation<P>(&self, p: P) -> io::Result<()>
- where P: Fn(&BD::Ctxt, BD::Idx) -> &Debug
+ where P: Fn(&BD, BD::Idx) -> &Debug
{
if let Some(ref path_str) = self.print_postflow_to {
let path = dataflow_path(BD::name(), "postflow", path_str);
}
pub struct DataflowAnalysis<'a, 'tcx: 'a, O>
- where O: BitDenotation, O::Ctxt: 'a
+ where O: BitDenotation
{
flow_state: DataflowState<O>,
mir: &'a Mir<'tcx>,
- ctxt: &'a O::Ctxt,
}
impl<'a, 'tcx: 'a, O> DataflowAnalysis<'a, 'tcx, O>
/// Specifies what index type is used to access the bitvector.
type Idx: Idx;
- /// Specifies what, if any, separate context needs to be supplied for methods below.
- type Ctxt;
-
/// A name describing the dataflow analysis that this
/// BitDenotation is supporting. The name should be something
/// suitable for plugging in as part of a filename e.g. avoid
fn name() -> &'static str;
/// Size of each bitvector allocated for each block in the analysis.
- fn bits_per_block(&self, &Self::Ctxt) -> usize;
+ fn bits_per_block(&self) -> usize;
/// Mutates the block-sets (the flow sets for the given
/// basic block) according to the effects that have been
/// (Typically this should only modify `sets.on_entry`, since the
/// gen and kill sets should reflect the effects of *executing*
/// the start block itself.)
- fn start_block_effect(&self, ctxt: &Self::Ctxt, sets: &mut BlockSets<Self::Idx>);
+ fn start_block_effect(&self, sets: &mut BlockSets<Self::Idx>);
/// Mutates the block-sets (the flow sets for the given
/// basic block) according to the effects of evaluating statement.
/// `bb_data` is the sequence of statements identifed by `bb` in
/// the MIR.
fn statement_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<Self::Idx>,
bb: mir::BasicBlock,
idx_stmt: usize);
/// The effects applied here cannot depend on which branch the
/// terminator took.
fn terminator_effect(&self,
- ctxt: &Self::Ctxt,
sets: &mut BlockSets<Self::Idx>,
bb: mir::BasicBlock,
idx_term: usize);
/// kill-sets associated with each edge coming out of the basic
/// block.
fn propagate_call_return(&self,
- ctxt: &Self::Ctxt,
in_out: &mut IdxSet<Self::Idx>,
call_bb: mir::BasicBlock,
dest_bb: mir::BasicBlock,
{
pub fn new(_tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &'a Mir<'tcx>,
- ctxt: &'a D::Ctxt,
denotation: D) -> Self {
- let bits_per_block = denotation.bits_per_block(&ctxt);
+ let bits_per_block = denotation.bits_per_block();
let usize_bits = mem::size_of::<usize>() * 8;
let words_per_block = (bits_per_block + usize_bits - 1) / usize_bits;
});
DataflowAnalysis {
- ctxt: ctxt,
mir: mir,
flow_state: DataflowState {
sets: AllSets {
// N.B.: This must be done *last*, after all other
// propagation, as documented in comment above.
self.flow_state.operator.propagate_call_return(
- &self.ctxt, in_out, bb, *dest_bb, dest_lval);
+ in_out, bb, *dest_bb, dest_lval);
self.propagate_bits_into_entry_set_for(in_out, changed, dest_bb);
}
}
use rustc_data_structures::indexed_vec::Idx;
use super::super::gather_moves::{MovePathIndex, LookupResult};
-use super::super::MoveDataParamEnv;
use super::BitDenotation;
use super::DataflowResults;
+use super::super::gather_moves::HasMoveData;
/// This function scans `mir` for all calls to the intrinsic
/// `rustc_peek` that have the expression form `rustc_peek(&expr)`.
mir: &Mir<'tcx>,
id: ast::NodeId,
_attributes: &[ast::Attribute],
- flow_ctxt: &O::Ctxt,
results: &DataflowResults<O>)
- where O: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
+ where O: BitDenotation<Idx=MovePathIndex> + HasMoveData<'tcx>
{
debug!("sanity_check_via_rustc_peek id: {:?}", id);
// FIXME: this is not DRY. Figure out way to abstract this and
// stuff, so such generalization may not be realistic.)
for bb in mir.basic_blocks().indices() {
- each_block(tcx, mir, flow_ctxt, results, bb);
+ each_block(tcx, mir, results, bb);
}
}
fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
mir: &Mir<'tcx>,
- ctxt: &O::Ctxt,
results: &DataflowResults<O>,
bb: mir::BasicBlock) where
- O: BitDenotation<Ctxt=MoveDataParamEnv<'tcx>, Idx=MovePathIndex>
+ O: BitDenotation<Idx=MovePathIndex> + HasMoveData<'tcx>
{
- let move_data = &ctxt.move_data;
+ let move_data = results.0.operator.move_data();
let mir::BasicBlockData { ref statements, ref terminator, is_cleanup: _ } = mir[bb];
let (args, span) = match is_rustc_peek(tcx, terminator) {
// reset GEN and KILL sets before emulating their effect.
for e in sets.gen_set.words_mut() { *e = 0; }
for e in sets.kill_set.words_mut() { *e = 0; }
- results.0.operator.statement_effect(ctxt, &mut sets, bb, j);
+ results.0.operator.statement_effect(&mut sets, bb, j);
sets.on_entry.union(sets.gen_set);
sets.on_entry.subtract(sets.kill_set);
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use super::gather_moves::{MoveData, MovePathIndex, LookupResult};
+use super::gather_moves::{HasMoveData, MoveData, MovePathIndex, LookupResult};
use super::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use super::dataflow::{DataflowResults};
use super::{drop_flag_effects_for_location, on_all_children_bits};
param_env: param_env
};
let flow_inits =
- super::do_dataflow(tcx, mir, id, &[], &env,
- MaybeInitializedLvals::new(tcx, mir));
+ super::do_dataflow(tcx, mir, id, &[],
+ MaybeInitializedLvals::new(tcx, mir, &env),
+ |bd, p| &bd.move_data().move_paths[p]);
let flow_uninits =
- super::do_dataflow(tcx, mir, id, &[], &env,
- MaybeUninitializedLvals::new(tcx, mir));
+ super::do_dataflow(tcx, mir, id, &[],
+ MaybeUninitializedLvals::new(tcx, mir, &env),
+ |bd, p| &bd.move_data().move_paths[p]);
ElaborateDropsCtxt {
tcx: tcx,
is_cleanup: bool)
-> Vec<BasicBlock>
{
- let mut succ = succ;
let mut unwind_succ = if is_cleanup {
None
} else {
c.unwind
};
- let mut update_drop_flag = true;
+
+ let mut succ = self.new_block(
+ c, c.is_cleanup, TerminatorKind::Goto { target: succ }
+ );
+
+ // Always clear the "master" drop flag at the bottom of the
+ // ladder. This is needed because the "master" drop flag
+ // protects the ADT's discriminant, which is invalidated
+ // after the ADT is dropped.
+ self.set_drop_flag(
+ Location { block: succ, statement_index: 0 },
+ c.path,
+ DropFlagState::Absent
+ );
fields.iter().rev().enumerate().map(|(i, &(ref lv, path))| {
- let drop_block = match path {
- Some(path) => {
- debug!("drop_ladder: for std field {} ({:?})", i, lv);
-
- self.elaborated_drop_block(&DropCtxt {
- source_info: c.source_info,
- is_cleanup: is_cleanup,
- init_data: c.init_data,
- lvalue: lv,
- path: path,
- succ: succ,
- unwind: unwind_succ,
- })
- }
- None => {
- debug!("drop_ladder: for rest field {} ({:?})", i, lv);
-
- let blk = self.complete_drop(&DropCtxt {
- source_info: c.source_info,
- is_cleanup: is_cleanup,
- init_data: c.init_data,
- lvalue: lv,
- path: c.path,
- succ: succ,
- unwind: unwind_succ,
- }, update_drop_flag);
-
- // the drop flag has been updated - updating
- // it again would clobber it.
- update_drop_flag = false;
-
- blk
- }
+ succ = if let Some(path) = path {
+ debug!("drop_ladder: for std field {} ({:?})", i, lv);
+
+ self.elaborated_drop_block(&DropCtxt {
+ source_info: c.source_info,
+ is_cleanup: is_cleanup,
+ init_data: c.init_data,
+ lvalue: lv,
+ path: path,
+ succ: succ,
+ unwind: unwind_succ,
+ })
+ } else {
+ debug!("drop_ladder: for rest field {} ({:?})", i, lv);
+
+ self.complete_drop(&DropCtxt {
+ source_info: c.source_info,
+ is_cleanup: is_cleanup,
+ init_data: c.init_data,
+ lvalue: lv,
+ path: c.path,
+ succ: succ,
+ unwind: unwind_succ,
+ }, false)
};
- succ = drop_block;
unwind_succ = unwind_ladder.as_ref().map(|p| p[i]);
-
- drop_block
+ succ
}).collect()
}
pub rev_lookup: MovePathLookup<'tcx>,
}
+pub trait HasMoveData<'tcx> {
+ fn move_data(&self) -> &MoveData<'tcx>;
+}
+
#[derive(Debug)]
pub struct LocationMap<T> {
/// Location-indexed (BasicBlock for outer index, index within BB
use borrowck::BorrowckCtxt;
use syntax::ast::{self, MetaItem};
-use syntax_pos::{Span, DUMMY_SP};
-
-use rustc::hir;
-use rustc::hir::intravisit::{FnKind};
+use syntax_pos::DUMMY_SP;
use rustc::mir::{self, BasicBlock, BasicBlockData, Mir, Statement, Terminator, Location};
use rustc::session::Session;
use self::dataflow::{Dataflow, DataflowAnalysis, DataflowResults};
use self::dataflow::{MaybeInitializedLvals, MaybeUninitializedLvals};
use self::dataflow::{DefinitelyInitializedLvals};
-use self::gather_moves::{MoveData, MovePathIndex, LookupResult};
+use self::gather_moves::{HasMoveData, MoveData, MovePathIndex, LookupResult};
+
+use std::fmt;
fn has_rustc_mir_with(attrs: &[ast::Attribute], name: &str) -> Option<MetaItem> {
for attr in attrs {
}
pub fn borrowck_mir(bcx: &mut BorrowckCtxt,
- fk: FnKind,
- _decl: &hir::FnDecl,
- body: &hir::Expr,
- _sp: Span,
id: ast::NodeId,
attributes: &[ast::Attribute]) {
- match fk {
- FnKind::ItemFn(name, ..) |
- FnKind::Method(name, ..) => {
- debug!("borrowck_mir({}) UNIMPLEMENTED", name);
- }
- FnKind::Closure(_) => {
- debug!("borrowck_mir closure (body.id={}) UNIMPLEMENTED", body.id);
- }
- }
-
let tcx = bcx.tcx;
- let param_env = ty::ParameterEnvironment::for_item(tcx, id);
-
- let mir = &tcx.item_mir(tcx.map.local_def_id(id));
+ let def_id = tcx.map.local_def_id(id);
+ debug!("borrowck_mir({}) UNIMPLEMENTED", tcx.item_path_str(def_id));
+ let mir = &tcx.item_mir(def_id);
+ let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let move_data = MoveData::gather_moves(mir, tcx, ¶m_env);
let mdpe = MoveDataParamEnv { move_data: move_data, param_env: param_env };
let flow_inits =
- do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeInitializedLvals::new(tcx, mir));
+ do_dataflow(tcx, mir, id, attributes, MaybeInitializedLvals::new(tcx, mir, &mdpe),
+ |bd, i| &bd.move_data().move_paths[i]);
let flow_uninits =
- do_dataflow(tcx, mir, id, attributes, &mdpe, MaybeUninitializedLvals::new(tcx, mir));
+ do_dataflow(tcx, mir, id, attributes, MaybeUninitializedLvals::new(tcx, mir, &mdpe),
+ |bd, i| &bd.move_data().move_paths[i]);
let flow_def_inits =
- do_dataflow(tcx, mir, id, attributes, &mdpe, DefinitelyInitializedLvals::new(tcx, mir));
+ do_dataflow(tcx, mir, id, attributes, DefinitelyInitializedLvals::new(tcx, mir, &mdpe),
+ |bd, i| &bd.move_data().move_paths[i]);
if has_rustc_mir_with(attributes, "rustc_peek_maybe_init").is_some() {
- dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &mdpe, &flow_inits);
+ dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &flow_inits);
}
if has_rustc_mir_with(attributes, "rustc_peek_maybe_uninit").is_some() {
- dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &mdpe, &flow_uninits);
+ dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &flow_uninits);
}
if has_rustc_mir_with(attributes, "rustc_peek_definite_init").is_some() {
- dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &mdpe, &flow_def_inits);
+ dataflow::sanity_check_via_rustc_peek(bcx.tcx, mir, id, attributes, &flow_def_inits);
}
if has_rustc_mir_with(attributes, "stop_after_dataflow").is_some() {
bcx: bcx,
mir: mir,
node_id: id,
- move_data: mdpe.move_data,
+ move_data: &mdpe.move_data,
flow_inits: flow_inits,
flow_uninits: flow_uninits,
};
debug!("borrowck_mir done");
}
-fn do_dataflow<'a, 'tcx, BD>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mir: &Mir<'tcx>,
- node_id: ast::NodeId,
- attributes: &[ast::Attribute],
- ctxt: &BD::Ctxt,
- bd: BD) -> DataflowResults<BD>
- where BD: BitDenotation<Idx=MovePathIndex, Ctxt=MoveDataParamEnv<'tcx>> + DataflowOperator
+fn do_dataflow<'a, 'tcx, BD, P>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ mir: &Mir<'tcx>,
+ node_id: ast::NodeId,
+ attributes: &[ast::Attribute],
+ bd: BD,
+ p: P)
+ -> DataflowResults<BD>
+ where BD: BitDenotation<Idx=MovePathIndex> + DataflowOperator,
+ P: Fn(&BD, BD::Idx) -> &fmt::Debug
{
let name_found = |sess: &Session, attrs: &[ast::Attribute], name| -> Option<String> {
if let Some(item) = has_rustc_mir_with(attrs, name) {
node_id: node_id,
print_preflow_to: print_preflow_to,
print_postflow_to: print_postflow_to,
- flow_state: DataflowAnalysis::new(tcx, mir, ctxt, bd),
+ flow_state: DataflowAnalysis::new(tcx, mir, bd),
};
- mbcx.dataflow(|ctxt, i| &ctxt.move_data.move_paths[i]);
+ mbcx.dataflow(p);
mbcx.flow_state.results()
}
-pub struct MirBorrowckCtxtPreDataflow<'a, 'tcx: 'a, BD>
- where BD: BitDenotation, BD::Ctxt: 'a
+pub struct MirBorrowckCtxtPreDataflow<'a, 'tcx: 'a, BD> where BD: BitDenotation
{
node_id: ast::NodeId,
flow_state: DataflowAnalysis<'a, 'tcx, BD>,
bcx: &'b mut BorrowckCtxt<'a, 'tcx>,
mir: &'b Mir<'tcx>,
node_id: ast::NodeId,
- move_data: MoveData<'tcx>,
+ move_data: &'b MoveData<'tcx>,
flow_inits: DataflowResults<MaybeInitializedLvals<'b, 'tcx>>,
flow_uninits: DataflowResults<MaybeUninitializedLvals<'b, 'tcx>>
}
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, id: ast::NodeId) {
+ b: hir::BodyId, s: Span, id: ast::NodeId) {
match fk {
FnKind::ItemFn(..) |
FnKind::Method(..) => {
}
fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem) {
- if let hir::ConstTraitItem(_, Some(ref expr)) = ti.node {
- gather_loans::gather_loans_in_static_initializer(self, ti.id, &expr);
+ if let hir::TraitItemKind::Const(_, Some(expr)) = ti.node {
+ gather_loans::gather_loans_in_static_initializer(self, ti.id, expr);
}
intravisit::walk_trait_item(self, ti);
}
fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem) {
- if let hir::ImplItemKind::Const(_, ref expr) = ii.node {
- gather_loans::gather_loans_in_static_initializer(self, ii.id, &expr);
+ if let hir::ImplItemKind::Const(_, expr) = ii.node {
+ gather_loans::gather_loans_in_static_initializer(self, ii.id, expr);
}
intravisit::walk_impl_item(self, ii);
}
// loan step is intended for things that have a data
// flow dependent conditions.
match item.node {
- hir::ItemStatic(.., ref ex) |
- hir::ItemConst(_, ref ex) => {
- gather_loans::gather_loans_in_static_initializer(this, item.id, &ex);
+ hir::ItemStatic(.., ex) |
+ hir::ItemConst(_, ex) => {
+ gather_loans::gather_loans_in_static_initializer(this, item.id, ex);
}
_ => { }
}
fn borrowck_fn<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
sp: Span,
id: ast::NodeId,
attributes: &[ast::Attribute]) {
debug!("borrowck_fn(id={})", id);
- let body = this.tcx.map.expr(body_id);
+ let body = this.tcx.map.body(body_id);
if attributes.iter().any(|item| item.check_name("rustc_mir_borrowck")) {
this.with_temp_region_map(id, |this| {
- mir::borrowck_mir(this, fk, decl, body, sp, id, attributes)
+ mir::borrowck_mir(this, id, attributes)
});
}
- let cfg = cfg::CFG::new(this.tcx, body);
+ let cfg = cfg::CFG::new(this.tcx, &body.value);
let AnalysisData { all_loans,
loans: loan_dfcx,
move_data: flowed_moves } =
- build_borrowck_dataflow_data(this, fk, decl, &cfg, body, sp, id);
+ build_borrowck_dataflow_data(this, &cfg, body, id);
move_data::fragments::instrument_move_fragments(&flowed_moves.move_data,
this.tcx,
&flowed_moves,
&all_loans[..],
id,
- decl,
body);
intravisit::walk_fn(this, fk, decl, body_id, sp, id);
}
fn build_borrowck_dataflow_data<'a, 'tcx>(this: &mut BorrowckCtxt<'a, 'tcx>,
- fk: FnKind<'tcx>,
- decl: &'tcx hir::FnDecl,
cfg: &cfg::CFG,
- body: &'tcx hir::Expr,
- sp: Span,
+ body: &'tcx hir::Body,
id: ast::NodeId)
-> AnalysisData<'a, 'tcx>
{
// Check the body of fn items.
let tcx = this.tcx;
- let id_range = intravisit::compute_id_range_for_fn_body(fk, decl, body, sp, id, &tcx.map);
+ let id_range = {
+ let mut visitor = intravisit::IdRangeComputingVisitor::new(&tcx.map);
+ visitor.visit_body(body);
+ visitor.result()
+ };
let (all_loans, move_data) =
- gather_loans::gather_loans_in_fn(this, id, decl, body);
+ gather_loans::gather_loans_in_fn(this, id, body);
let mut loan_dfcx =
DataFlowContext::new(this.tcx,
"borrowck",
- Some(decl),
+ Some(body),
cfg,
LoanDataFlowOperator,
id_range,
this.tcx,
cfg,
id_range,
- decl,
body);
AnalysisData { all_loans: all_loans,
}
};
- let body = tcx.map.expr(fn_parts.body);
+ let body = tcx.map.body(fn_parts.body);
let dataflow_data = build_borrowck_dataflow_data(&mut bccx,
- fn_parts.kind,
- &fn_parts.decl,
cfg,
body,
- fn_parts.span,
fn_parts.id);
(bccx, dataflow_data)
match tcx.map.get(closure_id) {
hir_map::NodeExpr(expr) => match expr.node {
hir::ExprClosure(.., body_id, _) => {
- body_id.node_id()
+ body_id.node_id
}
_ => {
bug!("encountered non-closure id: {}", closure_id)
if let Categorization::Deref(ref inner_cmt, ..) = err.cmt.cat {
if let Categorization::Local(local_id) = inner_cmt.cat {
let parent = self.tcx.map.get_parent_node(local_id);
- let opt_fn_decl = FnLikeNode::from_node(self.tcx.map.get(parent))
- .map(|fn_like| fn_like.decl());
- if let Some(fn_decl) = opt_fn_decl {
- if let Some(ref arg) = fn_decl.inputs.iter()
- .find(|ref arg| arg.pat.id == local_id) {
+ if let Some(fn_like) = FnLikeNode::from_node(self.tcx.map.get(parent)) {
+ if let Some(i) = self.tcx.map.body(fn_like.body()).arguments.iter()
+ .position(|arg| arg.pat.id == local_id) {
+ let arg_ty = &fn_like.decl().inputs[i];
if let hir::TyRptr(
opt_lifetime,
hir::MutTy{mutbl: hir::Mutability::MutImmutable, ref ty}) =
- arg.ty.node {
+ arg_ty.node {
if let Some(lifetime) = opt_lifetime {
if let Ok(snippet) = self.tcx.sess.codemap()
.span_to_snippet(ty.span) {
if let Ok(lifetime_snippet) = self.tcx.sess.codemap()
.span_to_snippet(lifetime.span) {
- db.span_label(arg.ty.span,
+ db.span_label(arg_ty.span,
&format!("use `&{} mut {}` \
here to make mutable",
lifetime_snippet,
}
}
else if let Ok(snippet) = self.tcx.sess.codemap()
- .span_to_snippet(arg.ty.span) {
+ .span_to_snippet(arg_ty.span) {
if snippet.starts_with("&") {
- db.span_label(arg.ty.span,
+ db.span_label(arg_ty.span,
&format!("use `{}` here to make mutable",
snippet.replace("&", "&mut ")));
}
tcx: TyCtxt<'a, 'tcx, 'tcx>,
cfg: &cfg::CFG,
id_range: IdRange,
- decl: &hir::FnDecl,
- body: &hir::Expr)
+ body: &hir::Body)
-> FlowedMoveData<'a, 'tcx> {
let mut dfcx_moves =
DataFlowContext::new(tcx,
"flowed_move_data_moves",
- Some(decl),
+ Some(body),
cfg,
MoveDataFlowOperator,
id_range,
let mut dfcx_assign =
DataFlowContext::new(tcx,
"flowed_move_data_assigns",
- Some(decl),
+ Some(body),
cfg,
AssignDataFlowOperator,
id_range,
let v = ctor.variant_for_adt(adt);
let qpath = hir::QPath::Resolved(None, P(hir::Path {
span: DUMMY_SP,
- global: false,
def: Def::Err,
segments: vec![hir::PathSegment::from_name(v.name)].into(),
}));
use rustc::hir::def::*;
use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
-use rustc::hir::print::pat_to_string;
use rustc::hir::{self, Pat, PatKind};
use rustc_back::slice;
impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::None
- }
-
- fn visit_expr(&mut self, _expr: &'tcx hir::Expr) {
- return // const, static and N in [T; N] - shouldn't contain anything
- }
-
- fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
- if let hir::ConstTraitItem(..) = item.node {
- return // nothing worth match checking in a constant
- } else {
- intravisit::walk_trait_item(self, item);
- }
- }
-
- fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
- if let hir::ImplItemKind::Const(..) = item.node {
- return // nothing worth match checking in a constant
- } else {
- intravisit::walk_impl_item(self, item);
- }
+ NestedVisitorMap::OnlyBodies(&self.tcx.map)
}
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, id: ast::NodeId) {
- if let FnKind::Closure(..) = fk {
- span_bug!(s, "check_match: closure outside of function")
- }
+ b: hir::BodyId, s: Span, id: ast::NodeId) {
+ intravisit::walk_fn(self, fk, fd, b, s, id);
MatchVisitor {
tcx: self.tcx,
param_env: &ty::ParameterEnvironment::for_item(self.tcx, id)
- }.visit_fn(fk, fd, b, s, id);
+ }.visit_body(self.tcx.map.body(b));
}
}
impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::OnlyBodies(&self.tcx.map)
+ NestedVisitorMap::None
}
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
self.check_patterns(false, slice::ref_slice(&loc.pat));
}
- fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
- b: hir::ExprId, s: Span, n: ast::NodeId) {
- intravisit::walk_fn(self, fk, fd, b, s, n);
+ fn visit_body(&mut self, body: &'tcx hir::Body) {
+ intravisit::walk_body(self, body);
- for input in &fd.inputs {
- self.check_irrefutable(&input.pat, true);
- self.check_patterns(false, slice::ref_slice(&input.pat));
+ for arg in &body.arguments {
+ self.check_irrefutable(&arg.pat, true);
+ self.check_patterns(false, slice::ref_slice(&arg.pat));
}
}
}
Useful => bug!()
};
- let pattern_string = pat_to_string(witness[0].single_pattern());
+ let pattern_string = hir::print::to_string(&self.tcx.map, |s| {
+ s.print_pat(witness[0].single_pattern())
+ });
let mut diag = struct_span_err!(
self.tcx.sess, pat.span, E0005,
"refutable pattern in {}: `{}` not covered",
},
_ => bug!(),
};
- let pattern_string = pat_to_string(witness);
+ let pattern_string = hir::print::to_string(&cx.tcx.map, |s| {
+ s.print_pat(witness)
+ });
struct_span_err!(cx.tcx.sess, sp, E0297,
"refutable pattern in `for` loop binding: \
`{}` not covered",
},
_ => {
let pattern_strings: Vec<_> = witnesses.iter().map(|w| {
- pat_to_string(w)
+ hir::print::to_string(&cx.tcx.map, |s| s.print_pat(w))
}).collect();
const LIMIT: usize = 3;
let joined_patterns = match pattern_strings.len() {
E0306: r##"
-In an array literal `[x; N]`, `N` is the number of elements in the array. This
+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
-let x = [0i32; true]; // error: expected positive integer for repeat count,
- // found boolean
+const X: [i32; true] = [0]; // error: expected `usize` for array length,
+ // found boolean
```
Working example:
```
-let x = [0i32; 2];
+const X: [i32; 1] = [0];
```
"##,
}
use rustc::hir::map as ast_map;
use rustc::hir::map::blocks::FnLikeNode;
-use rustc::middle::cstore::InlinedItem;
use rustc::traits;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
fn lookup_variant_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
variant_def: DefId)
-> Option<&'tcx Expr> {
- fn variant_expr<'a>(variants: &'a [hir::Variant], id: ast::NodeId)
- -> Option<&'a Expr> {
+ let variant_expr = |variants: &'tcx [hir::Variant], id: ast::NodeId |
+ -> Option<&'tcx Expr> {
for variant in variants {
if variant.node.data.id() == id {
- return variant.node.disr_expr.as_ref().map(|e| &**e);
+ return variant.node.disr_expr.map(|e| {
+ &tcx.map.body(e).value
+ });
}
}
None
- }
+ };
if let Some(variant_node_id) = tcx.map.as_local_node_id(variant_def) {
let enum_node_id = tcx.map.get_parent(variant_node_id);
match tcx.map.find(node_id) {
None => None,
Some(ast_map::NodeItem(it)) => match it.node {
- hir::ItemConst(ref ty, ref const_expr) => {
- Some((&const_expr, tcx.ast_ty_to_prim_ty(ty)))
+ hir::ItemConst(ref ty, body) => {
+ Some((&tcx.map.body(body).value,
+ tcx.ast_ty_to_prim_ty(ty)))
}
_ => None
},
Some(ast_map::NodeTraitItem(ti)) => match ti.node {
- hir::ConstTraitItem(ref ty, ref expr_option) => {
+ 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.map.get_parent(node_id);
let trait_id = tcx.map.local_def_id(trait_id);
- let default_value = expr_option.as_ref()
- .map(|expr| (&**expr, tcx.ast_ty_to_prim_ty(ty)));
+ let default_value = default.map(|body| {
+ (&tcx.map.body(body).value,
+ 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
_ => None
},
Some(ast_map::NodeImplItem(ii)) => match ii.node {
- hir::ImplItemKind::Const(ref ty, ref expr) => {
- Some((&expr, tcx.ast_ty_to_prim_ty(ty)))
+ hir::ImplItemKind::Const(ref ty, body) => {
+ Some((&tcx.map.body(body).value,
+ tcx.ast_ty_to_prim_ty(ty)))
}
_ => None
},
Some(_) => None
}
} else {
- match tcx.extern_const_statics.borrow().get(&def_id) {
- Some(&None) => return None,
- Some(&Some((expr_id, ty))) => {
- return Some((tcx.map.expect_expr(expr_id), ty));
- }
- None => {}
- }
- let mut used_substs = false;
- let expr_ty = match tcx.sess.cstore.maybe_get_item_ast(tcx, def_id) {
- Some((&InlinedItem { body: ref const_expr, .. }, _)) => {
- Some((&**const_expr, Some(tcx.sess.cstore.item_type(tcx, def_id))))
- }
- _ => None
- };
- let expr_ty = match tcx.sess.cstore.describe_def(def_id) {
+ let expr_ty = tcx.sess.cstore.maybe_get_item_body(tcx, def_id).map(|body| {
+ (&body.value, Some(tcx.sess.cstore.item_type(tcx, def_id)))
+ });
+ match tcx.sess.cstore.describe_def(def_id) {
Some(Def::AssociatedConst(_)) => {
let trait_id = tcx.sess.cstore.trait_of_item(def_id);
// As mentioned in the comments above for in-crate
// trait-associated const if the caller gives us the
// substitutions for the reference to it.
if let Some(trait_id) = trait_id {
- used_substs = true;
-
if let Some(substs) = substs {
resolve_trait_associated_const(tcx, def_id, expr_ty, trait_id, substs)
} else {
},
Some(Def::Const(..)) => expr_ty,
_ => None
- };
- // If we used the substitutions, particularly to choose an impl
- // of a trait-associated const, don't cache that, because the next
- // lookup with the same def_id may yield a different result.
- if !used_substs {
- tcx.extern_const_statics
- .borrow_mut()
- .insert(def_id, expr_ty.map(|(e, t)| (e.id, t)));
}
- expr_ty
}
}
-fn inline_const_fn_from_external_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId)
- -> Option<ast::NodeId> {
- match tcx.extern_const_fns.borrow().get(&def_id) {
- Some(&ast::DUMMY_NODE_ID) => return None,
- Some(&fn_id) => return Some(fn_id),
- None => {}
- }
-
- if !tcx.sess.cstore.is_const_fn(def_id) {
- tcx.extern_const_fns.borrow_mut().insert(def_id, ast::DUMMY_NODE_ID);
- return None;
- }
-
- let fn_id = tcx.sess.cstore.maybe_get_item_ast(tcx, def_id).map(|t| t.1);
- tcx.extern_const_fns.borrow_mut().insert(def_id,
- fn_id.unwrap_or(ast::DUMMY_NODE_ID));
- fn_id
-}
-
-pub enum ConstFnNode<'tcx> {
- Local(FnLikeNode<'tcx>),
- Inlined(&'tcx InlinedItem)
-}
-
-pub fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
- -> Option<ConstFnNode<'tcx>>
+fn lookup_const_fn_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
+ -> Option<&'tcx hir::Body>
{
- let fn_id = if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
- node_id
- } else {
- if let Some(fn_id) = inline_const_fn_from_external_crate(tcx, def_id) {
- if let ast_map::NodeInlinedItem(ii) = tcx.map.get(fn_id) {
- return Some(ConstFnNode::Inlined(ii));
+ if let Some(node_id) = tcx.map.as_local_node_id(def_id) {
+ FnLikeNode::from_node(tcx.map.get(node_id)).and_then(|fn_like| {
+ if fn_like.constness() == hir::Constness::Const {
+ Some(tcx.map.body(fn_like.body()))
} else {
- bug!("Got const fn from external crate, but it's not inlined")
+ None
}
+ })
+ } else {
+ if tcx.sess.cstore.is_const_fn(def_id) {
+ tcx.sess.cstore.maybe_get_item_body(tcx, def_id)
} else {
- return None;
+ None
}
- };
-
- let fn_like = match FnLikeNode::from_node(tcx.map.get(fn_id)) {
- Some(fn_like) => fn_like,
- None => return None
- };
-
- if fn_like.constness() == hir::Constness::Const {
- Some(ConstFnNode::Local(fn_like))
- } else {
- None
}
}
Struct(_) => signal!(e, UnimplementedConstVal("tuple struct constructors")),
callee => signal!(e, CallOn(callee)),
};
- let (arg_defs, body_id) = match lookup_const_fn_by_id(tcx, did) {
- Some(ConstFnNode::Inlined(ii)) => (ii.const_fn_args.clone(), ii.body.expr_id()),
- Some(ConstFnNode::Local(fn_like)) =>
- (fn_like.decl().inputs.iter()
- .map(|arg| match arg.pat.node {
- hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
- _ => None
- }).collect(),
- fn_like.body()),
+ let body = match lookup_const_fn_by_id(tcx, did) {
+ Some(body) => body,
None => signal!(e, NonConstPath),
};
- let result = tcx.map.expr(body_id);
+
+ let arg_defs = body.arguments.iter().map(|arg| match arg.pat.node {
+ hir::PatKind::Binding(_, def_id, _, _) => Some(def_id),
+ _ => None
+ }).collect::<Vec<_>>();
assert_eq!(arg_defs.len(), args.len());
let mut call_args = DefIdMap();
}
}
debug!("const call({:?})", call_args);
- eval_const_expr_partial(tcx, &result, ty_hint, Some(&call_args))?
+ eval_const_expr_partial(tcx, &body.value, ty_hint, Some(&call_args))?
},
hir::ExprLit(ref lit) => match lit_to_const(&lit.node, tcx, ety) {
Ok(val) => val,
}
}
hir::ExprArray(ref v) => Array(e.id, v.len() as u64),
- hir::ExprRepeat(_, ref n) => {
+ hir::ExprRepeat(_, n) => {
let len_hint = ty_hint.checked_or(tcx.types.usize);
+ let n = &tcx.map.body(n).value;
Repeat(
e.id,
- match eval_const_expr_partial(tcx, &n, len_hint, fn_args)? {
+ match eval_const_expr_partial(tcx, n, len_hint, fn_args)? {
Integral(Usize(i)) => i.as_u64(tcx.sess.target.uint_type),
Integral(_) => signal!(e, RepeatCountNotNatural),
_ => signal!(e, RepeatCountNotInt),
if let hir::ExprPath(hir::QPath::Resolved(None, ref path)) = count_expr.node {
if let Def::Local(..) = path.def {
- diag.note(&format!("`{}` is a variable", path));
+ diag.note(&format!("`{}` is a variable",
+ tcx.map.node_to_pretty_string(count_expr.id)));
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
});
+ let whitelisted_legacy_custom_derives = registry.take_whitelisted_custom_derives();
let Registry { syntax_exts, early_lint_passes, late_lint_passes, lint_groups,
llvm_passes, attributes, mir_passes, .. } = registry;
let resolver_arenas = Resolver::arenas();
let mut resolver =
Resolver::new(sess, &krate, make_glob_map, &mut crate_loader, &resolver_arenas);
+ resolver.whitelisted_legacy_custom_derives = whitelisted_legacy_custom_derives;
syntax_ext::register_builtins(&mut resolver, syntax_exts, sess.features.borrow().quote);
krate = time(time_passes, "expansion", || {
Some(ref n) if *n == "rlib" => {
Some(config::CrateTypeRlib)
}
- Some(ref n) if *n == "metadata" => {
- Some(config::CrateTypeMetadata)
- }
Some(ref n) if *n == "dylib" => {
Some(config::CrateTypeDylib)
}
control.after_hir_lowering.stop = Compilation::Stop;
}
- if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe) {
+ if !sess.opts.output_types.keys().any(|&i| i == OutputType::Exe ||
+ i == OutputType::Metadata) {
control.after_llvm.stop = Compilation::Stop;
}
use std::str::FromStr;
use rustc::hir::map as hir_map;
-use rustc::hir::map::{blocks, NodePrinter};
+use rustc::hir::map::blocks;
use rustc::hir;
use rustc::hir::print as pprust_hir;
}
impl<'ast> pprust::PpAnn for NoAnn<'ast> {}
-impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {}
+impl<'ast> pprust_hir::PpAnn for NoAnn<'ast> {
+ fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+ -> io::Result<()> {
+ if let Some(ref map) = self.ast_map {
+ pprust_hir::PpAnn::nested(map, state, nested)
+ } else {
+ Ok(())
+ }
+ }
+}
struct IdentifiedAnnotation<'ast> {
sess: &'ast Session,
}
impl<'ast> pprust_hir::PpAnn for IdentifiedAnnotation<'ast> {
+ fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+ -> io::Result<()> {
+ if let Some(ref map) = self.ast_map {
+ pprust_hir::PpAnn::nested(map, state, nested)
+ } else {
+ Ok(())
+ }
+ }
fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
match node {
pprust_hir::NodeExpr(_) => s.popen(),
}
impl<'a, 'tcx> pprust_hir::PpAnn for TypedAnnotation<'a, 'tcx> {
+ fn nested(&self, state: &mut pprust_hir::State, nested: pprust_hir::Nested)
+ -> io::Result<()> {
+ pprust_hir::PpAnn::nested(&self.tcx.map, state, nested)
+ }
fn pre(&self, s: &mut pprust_hir::State, node: pprust_hir::AnnNode) -> io::Result<()> {
match node {
pprust_hir::NodeExpr(_) => s.popen(),
let cfg = match code {
blocks::Code::Expr(expr) => cfg::CFG::new(tcx, expr),
blocks::Code::FnLike(fn_like) => {
- let body = tcx.map.expr(fn_like.body());
- cfg::CFG::new(tcx, body)
+ let body = tcx.map.body(fn_like.body());
+ cfg::CFG::new(tcx, &body.value)
},
};
let labelled_edges = mode != PpFlowGraphMode::UnlabelledEdges;
&mut rdr,
box out,
annotation.pp_ann(),
- true,
- Some(ast_map.krate()));
+ true);
for node_id in uii.all_matching_node_ids(ast_map) {
let node = ast_map.get(node_id);
- pp_state.print_node(&node)?;
+ pp_state.print_node(node)?;
pp::space(&mut pp_state.s)?;
let path = annotation.node_path(node_id)
.expect("--unpretty missing node paths");
self.process_attrs(item.id, &item.attrs);
}
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+ self.process_attrs(trait_item.id, &trait_item.attrs);
+ }
+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.process_attrs(impl_item.id, &impl_item.attrs);
}
visit::walk_item(self, item);
}
+ fn visit_trait_item(&mut self, trait_item: &'tcx hir::TraitItem) {
+ self.calculate_node_id(trait_item.id, |v| v.visit_trait_item(trait_item));
+ visit::walk_trait_item(self, trait_item);
+ }
+
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
self.calculate_node_id(impl_item.id, |v| v.visit_impl_item(impl_item));
visit::walk_impl_item(self, impl_item);
}
-
- fn visit_foreign_item(&mut self, item: &'tcx hir::ForeignItem) {
- self.calculate_node_id(item.id, |v| v.visit_foreign_item(item));
- visit::walk_foreign_item(self, item);
- }
}
use rustc::hir::intravisit as visit;
use rustc::ty::TyCtxt;
use rustc_data_structures::fnv;
-use std::hash::Hash;
+use std::hash::{Hash, Hasher};
use super::def_path_hash::DefPathHashes;
use super::caching_codemap_view::CachingCodemapView;
SawLifetimeDef(usize),
SawMod,
- SawForeignItem,
+ SawForeignItem(SawForeignItemComponent),
SawItem(SawItemComponent),
SawTy(SawTyComponent),
+ SawFnDecl(bool),
SawGenerics,
SawTraitItem(SawTraitOrImplItemComponent),
SawImplItem(SawTraitOrImplItemComponent),
SawStructField,
- SawVariant,
+ SawVariant(bool),
SawQPath,
- SawPath(bool),
SawPathSegment,
SawPathParameters,
SawBlock,
SawExprPath,
SawExprAddrOf(hir::Mutability),
SawExprRet,
- SawExprInlineAsm(&'a hir::InlineAsm),
+ SawExprInlineAsm(StableInlineAsm<'a>),
SawExprStruct,
SawExprRepeat,
}
ExprBreak(label, _) => (SawExprBreak(label.map(|l| l.name.as_str())), false),
ExprAgain(label) => (SawExprAgain(label.map(|l| l.name.as_str())), false),
ExprRet(..) => (SawExprRet, false),
- ExprInlineAsm(ref a,..) => (SawExprInlineAsm(a), false),
+ ExprInlineAsm(ref a,..) => (SawExprInlineAsm(StableInlineAsm(a)), false),
ExprStruct(..) => (SawExprStruct, false),
ExprRepeat(..) => (SawExprRepeat, false),
}
SawItemConst,
SawItemFn(Unsafety, Constness, Abi),
SawItemMod,
- SawItemForeignMod,
+ SawItemForeignMod(Abi),
SawItemTy,
SawItemEnum,
SawItemStruct,
ItemConst(..) =>SawItemConst,
ItemFn(_, unsafety, constness, abi, _, _) => SawItemFn(unsafety, constness, abi),
ItemMod(..) => SawItemMod,
- ItemForeignMod(..) => SawItemForeignMod,
+ ItemForeignMod(ref fm) => SawItemForeignMod(fm.abi),
ItemTy(..) => SawItemTy,
ItemEnum(..) => SawItemEnum,
ItemStruct(..) => SawItemStruct,
}
}
+#[derive(Hash)]
+enum SawForeignItemComponent {
+ Static { mutable: bool },
+ Fn,
+}
+
#[derive(Hash)]
enum SawPatComponent {
SawPatWild,
SawTraitOrImplItemType
}
-fn saw_trait_item(ti: &TraitItem_) -> SawTraitOrImplItemComponent {
+fn saw_trait_item(ti: &TraitItemKind) -> SawTraitOrImplItemComponent {
match *ti {
- ConstTraitItem(..) => SawTraitOrImplItemConst,
- MethodTraitItem(ref sig, ref body) =>
- SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, body.is_some()),
- TypeTraitItem(..) => SawTraitOrImplItemType
+ TraitItemKind::Const(..) => SawTraitOrImplItemConst,
+ TraitItemKind::Method(ref sig, TraitMethod::Required(_)) =>
+ SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, false),
+ TraitItemKind::Method(ref sig, TraitMethod::Provided(_)) =>
+ SawTraitOrImplItemMethod(sig.unsafety, sig.constness, sig.abi, true),
+ TraitItemKind::Type(..) => SawTraitOrImplItemType
}
}
SomeExpansion,
}
+/// A wrapper that provides a stable Hash implementation.
+struct StableInlineAsm<'a>(&'a InlineAsm);
+
+impl<'a> Hash for StableInlineAsm<'a> {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ let InlineAsm {
+ asm,
+ asm_str_style,
+ ref outputs,
+ ref inputs,
+ ref clobbers,
+ volatile,
+ alignstack,
+ dialect,
+ expn_id: _, // This is used for error reporting
+ } = *self.0;
+
+ asm.as_str().hash(state);
+ asm_str_style.hash(state);
+ outputs.len().hash(state);
+ for output in outputs {
+ let InlineAsmOutput { constraint, is_rw, is_indirect } = *output;
+ constraint.as_str().hash(state);
+ is_rw.hash(state);
+ is_indirect.hash(state);
+ }
+ inputs.len().hash(state);
+ for input in inputs {
+ input.as_str().hash(state);
+ }
+ clobbers.len().hash(state);
+ for clobber in clobbers {
+ clobber.as_str().hash(state);
+ }
+ volatile.hash(state);
+ alignstack.hash(state);
+ dialect.hash(state);
+ }
+}
+
macro_rules! hash_attrs {
($visitor:expr, $attrs:expr) => ({
let attrs = $attrs;
g: &'tcx Generics,
item_id: NodeId) {
debug!("visit_variant: st={:?}", self.st);
- SawVariant.hash(self.st);
+ SawVariant(v.node.disr_expr.is_some()).hash(self.st);
hash_attrs!(self, &v.node.attrs);
visit::walk_variant(self, v, g, item_id)
}
// implicitly hashing the discriminant of SawExprComponent.
hash_span!(self, ex.span, force_span);
hash_attrs!(self, &ex.attrs);
- visit::walk_expr(self, ex)
+
+ // Always hash nested constant bodies (e.g. n in `[x; n]`).
+ let hash_bodies = self.hash_bodies;
+ self.hash_bodies = true;
+ visit::walk_expr(self, ex);
+ self.hash_bodies = hash_bodies;
}
fn visit_stmt(&mut self, s: &'tcx Stmt) {
fn visit_foreign_item(&mut self, i: &'tcx ForeignItem) {
debug!("visit_foreign_item: st={:?}", self.st);
- SawForeignItem.hash(self.st);
+ match i.node {
+ ForeignItemFn(..) => {
+ SawForeignItem(SawForeignItemComponent::Fn)
+ }
+ ForeignItemStatic(_, mutable) => {
+ SawForeignItem(SawForeignItemComponent::Static {
+ mutable: mutable
+ })
+ }
+ }.hash(self.st);
+
hash_span!(self, i.span);
hash_attrs!(self, &i.attrs);
visit::walk_foreign_item(self, i)
debug!("visit_ty: st={:?}", self.st);
SawTy(saw_ty(&t.node)).hash(self.st);
hash_span!(self, t.span);
- visit::walk_ty(self, t)
+
+ // Always hash nested constant bodies (e.g. N in `[T; N]`).
+ let hash_bodies = self.hash_bodies;
+ self.hash_bodies = true;
+ visit::walk_ty(self, t);
+ self.hash_bodies = hash_bodies;
}
fn visit_generics(&mut self, g: &'tcx Generics) {
visit::walk_generics(self, g)
}
+ fn visit_fn_decl(&mut self, fd: &'tcx FnDecl) {
+ debug!("visit_fn_decl: st={:?}", self.st);
+ SawFnDecl(fd.variadic).hash(self.st);
+ visit::walk_fn_decl(self, fd)
+ }
+
fn visit_trait_item(&mut self, ti: &'tcx TraitItem) {
debug!("visit_trait_item: st={:?}", self.st);
fn visit_path(&mut self, path: &'tcx Path, _: ast::NodeId) {
debug!("visit_path: st={:?}", self.st);
- SawPath(path.global).hash(self.st);
hash_span!(self, path.span);
visit::walk_path(self, path)
}
// These fields are handled separately:
exported_macros: _,
items: _,
+ trait_items: _,
impl_items: _,
- exprs: _,
+ bodies: _,
} = *krate;
visit::Visitor::visit_mod(self, module, span, ast::CRATE_NODE_ID);
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
cx: &LateContext,
fk: FnKind,
_: &hir::FnDecl,
- _: &hir::Expr,
+ _: &hir::Body,
span: Span,
id: ast::NodeId) {
match fk {
}
}
- fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
- if let hir::MethodTraitItem(_, None) = trait_item.node {
+ fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
+ if let hir::TraitItemKind::Method(_, hir::TraitMethod::Required(ref names)) = item.node {
self.check_snake_case(cx,
"trait method",
- &trait_item.name.as_str(),
- Some(trait_item.span));
+ &item.name.as_str(),
+ Some(item.span));
+ for name in names {
+ self.check_snake_case(cx, "variable", &name.node.as_str(), Some(name.span));
+ }
}
}
}
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
- // Exclude parameter names from foreign functions
- let parent_node = cx.tcx.map.get_parent_node(p.id);
- if let hir::map::NodeForeignItem(item) = cx.tcx.map.get(parent_node) {
- if let hir::ForeignItemFn(..) = item.node {
- return;
- }
- }
-
if let &PatKind::Binding(_, _, ref path1, _) = &p.node {
self.check_snake_case(cx, "variable", &path1.node.as_str(), Some(p.span));
}
fn check_trait_item(&mut self, cx: &LateContext, ti: &hir::TraitItem) {
match ti.node {
- hir::ConstTraitItem(..) => {
+ hir::TraitItemKind::Const(..) => {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", ti.name, ti.span);
}
_ => {}
fn check_pat(&mut self, cx: &LateContext, p: &hir::Pat) {
// Lint for constants that look like binding identifiers (#7526)
if let PatKind::Path(hir::QPath::Resolved(None, ref path)) = p.node {
- if !path.global && path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
+ if path.segments.len() == 1 && path.segments[0].parameters.is_empty() {
if let Def::Const(..) = path.def {
NonUpperCaseGlobals::check_upper_case(cx,
"constant in pattern",
cx: &LateContext,
fk: FnKind<'tcx>,
_: &hir::FnDecl,
- _: &hir::Expr,
+ _: &hir::Body,
span: Span,
_: ast::NodeId) {
match fk {
}
}
- fn check_trait_item(&mut self, cx: &LateContext, trait_item: &hir::TraitItem) {
- if let hir::MethodTraitItem(ref sig, None) = trait_item.node {
+ fn check_trait_item(&mut self, cx: &LateContext, item: &hir::TraitItem) {
+ if let hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(_)) = item.node {
if sig.unsafety == hir::Unsafety::Unsafe {
cx.span_lint(UNSAFE_CODE,
- trait_item.span,
+ item.span,
"declaration of an `unsafe` method")
}
}
hir::ItemEnum(..) => "an enum",
hir::ItemStruct(..) => "a struct",
hir::ItemUnion(..) => "a union",
- hir::ItemTrait(.., ref items) => {
+ hir::ItemTrait(.., ref trait_item_refs) => {
// Issue #11592, traits are always considered exported, even when private.
if it.vis == hir::Visibility::Inherited {
self.private_traits.insert(it.id);
- for itm in items {
- self.private_traits.insert(itm.id);
+ for trait_item_ref in trait_item_refs {
+ self.private_traits.insert(trait_item_ref.id.node_id);
}
return;
}
}
let desc = match trait_item.node {
- hir::ConstTraitItem(..) => "an associated constant",
- hir::MethodTraitItem(..) => "a trait method",
- hir::TypeTraitItem(..) => "an associated type",
+ hir::TraitItemKind::Const(..) => "an associated constant",
+ hir::TraitItemKind::Method(..) => "a trait method",
+ hir::TraitItemKind::Type(..) => "an associated type",
};
self.check_missing_docs_attrs(cx,
cx: &LateContext,
fn_kind: FnKind,
_: &hir::FnDecl,
- blk: &hir::Expr,
+ body: &hir::Body,
sp: Span,
id: ast::NodeId) {
let method = match fn_kind {
// to have behaviour like the above, rather than
// e.g. accidentally recurring after an assert.
- let cfg = cfg::CFG::new(cx.tcx, blk);
+ let cfg = cfg::CFG::new(cx.tcx, &body.value);
let mut work_queue = vec![cfg.entry];
let mut reached_exit_without_self_call = false;
let sig = self.cx.tcx.erase_late_bound_regions(&sig);
for (input_ty, input_hir) in sig.inputs().iter().zip(&decl.inputs) {
- self.check_type_for_ffi_and_report_errors(input_hir.ty.span, input_ty);
+ self.check_type_for_ffi_and_report_errors(input_hir.span, input_ty);
}
if let hir::Return(ref ret_hir) = decl.output {
if nmod.abi != Abi::RustIntrinsic && nmod.abi != Abi::PlatformIntrinsic {
for ni in &nmod.items {
match ni.node {
- hir::ForeignItemFn(ref decl, _) => {
+ hir::ForeignItemFn(ref decl, _, _) => {
vis.check_foreign_fn(ni.id, decl);
}
hir::ForeignItemStatic(ref ty, _) => {
fn check_fn(&mut self,
cx: &LateContext,
_: FnKind,
- decl: &hir::FnDecl,
- _: &hir::Expr,
+ _: &hir::FnDecl,
+ body: &hir::Body,
_: Span,
_: ast::NodeId) {
- for a in &decl.inputs {
+ for a in &body.arguments {
self.check_unused_mut_pat(cx, slice::ref_slice(&a.pat));
}
}
let is_crossed = target != host;
let optional_components =
- ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430"];
+ ["x86", "arm", "aarch64", "mips", "powerpc", "pnacl", "systemz", "jsbackend", "msp430",
+ "sparc", "nvptx"];
// FIXME: surely we don't need all these components, right? Stuff like mcjit
// or interpreter the compiler itself never uses.
X86StdcallCallConv = 64,
X86FastcallCallConv = 65,
ArmAapcsCallConv = 67,
+ PtxKernel = 71,
X86_64_SysV = 78,
X86_64_Win64 = 79,
X86_VectorCall = 80,
StructRet = 16,
UWTable = 17,
ZExt = 18,
+ InReg = 19,
}
/// LLVMIntPredicate
// generates an llvmdeps.rs file next to this one which will be
// automatically updated whenever LLVM is updated to include an up-to-date
// set of the libraries we need to link to LLVM for.
-#[cfg_attr(not(all(stage0,cargobuild)),
- link(name = "rustllvm", kind = "static"))] // not quite true but good enough
-#[cfg_attr(stage0, linked_from = "rustllvm")]
+#[link(name = "rustllvm", kind = "static")] // not quite true but good enough
extern "C" {
// Create and destroy contexts.
pub fn LLVMContextCreate() -> ContextRef;
#![feature(concat_idents)]
#![feature(libc)]
#![feature(link_args)]
-#![cfg_attr(stage0, feature(linked_from))]
#![feature(staged_api)]
-#![cfg_attr(not(stage0), feature(rustc_private))]
+#![feature(rustc_private)]
extern crate libc;
#[macro_use]
/// Safe wrapper around `LLVMGetParam`, because segfaults are no fun.
pub fn get_param(llfn: ValueRef, index: c_uint) -> ValueRef {
unsafe {
- assert!(index < LLVMCountParams(llfn));
+ assert!(index < LLVMCountParams(llfn),
+ "out of bounds argument access: {} out of {} arguments", index, LLVMCountParams(llfn));
LLVMGetParam(llfn, index)
}
}
LLVMInitializeMSP430Target,
LLVMInitializeMSP430TargetMC,
LLVMInitializeMSP430AsmPrinter);
+ init_target!(llvm_component = "sparc",
+ LLVMInitializeSparcTargetInfo,
+ LLVMInitializeSparcTarget,
+ LLVMInitializeSparcTargetMC,
+ LLVMInitializeSparcAsmPrinter,
+ LLVMInitializeSparcAsmParser);
+ init_target!(llvm_component = "nvptx",
+ LLVMInitializeNVPTXTargetInfo,
+ LLVMInitializeNVPTXTarget,
+ LLVMInitializeNVPTXTargetMC,
+ LLVMInitializeNVPTXAsmPrinter);
}
pub fn last_error() -> Option<String> {
use encoder::EncodeContext;
use schema::*;
-use rustc::middle::cstore::{InlinedItem, InlinedItemRef};
-use rustc::middle::const_qualif::ConstQualif;
+use rustc::hir;
use rustc::hir::def::Def;
use rustc::hir::def_id::DefId;
use rustc::ty::{self, TyCtxt, Ty};
#[derive(RustcEncodable, RustcDecodable)]
pub struct Ast<'tcx> {
id_range: IdRange,
- item: Lazy<InlinedItem>,
+ body: Lazy<hir::Body>,
side_tables: LazySeq<(ast::NodeId, TableEntry<'tcx>)>,
+ pub nested_bodies: LazySeq<hir::Body>,
+ pub rvalue_promotable_to_static: bool,
}
#[derive(RustcEncodable, RustcDecodable)]
NodeType(Ty<'tcx>),
ItemSubsts(ty::ItemSubsts<'tcx>),
Adjustment(ty::adjustment::Adjustment<'tcx>),
- ConstQualif(ConstQualif),
}
impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
- pub fn encode_inlined_item(&mut self, ii: InlinedItemRef<'tcx>) -> Lazy<Ast<'tcx>> {
+ pub fn encode_body(&mut self, body: hir::BodyId) -> Lazy<Ast<'tcx>> {
+ let body = self.tcx.map.body(body);
+
let mut id_visitor = IdRangeComputingVisitor::new(&self.tcx.map);
- ii.visit(&mut id_visitor);
+ id_visitor.visit_body(body);
- let ii_pos = self.position();
- ii.encode(self).unwrap();
+ let body_pos = self.position();
+ body.encode(self).unwrap();
let tables_pos = self.position();
let tables_count = {
ecx: self,
count: 0,
};
- ii.visit(&mut visitor);
+ visitor.visit_body(body);
visitor.count
};
+ let nested_pos = self.position();
+ let nested_count = {
+ let mut visitor = NestedBodyEncodingVisitor {
+ ecx: self,
+ count: 0,
+ };
+ visitor.visit_body(body);
+ visitor.count
+ };
+
+ let rvalue_promotable_to_static =
+ self.tcx.rvalue_promotable_to_static.borrow()[&body.value.id];
+
self.lazy(&Ast {
id_range: id_visitor.result(),
- item: Lazy::with_position(ii_pos),
+ body: Lazy::with_position(body_pos),
side_tables: LazySeq::with_position_and_length(tables_pos, tables_count),
+ nested_bodies: LazySeq::with_position_and_length(nested_pos, nested_count),
+ rvalue_promotable_to_static: rvalue_promotable_to_static
})
}
}
encode(tcx.tables().node_types.get(&id).cloned().map(TableEntry::NodeType));
encode(tcx.tables().item_substs.get(&id).cloned().map(TableEntry::ItemSubsts));
encode(tcx.tables().adjustments.get(&id).cloned().map(TableEntry::Adjustment));
- encode(tcx.const_qualif_map.borrow().get(&id).cloned().map(TableEntry::ConstQualif));
}
}
-/// Decodes an item from its AST in the cdata's metadata and adds it to the
+struct NestedBodyEncodingVisitor<'a, 'b: 'a, 'tcx: 'b> {
+ ecx: &'a mut EncodeContext<'b, 'tcx>,
+ count: usize,
+}
+
+impl<'a, 'b, 'tcx> Visitor<'tcx> for NestedBodyEncodingVisitor<'a, 'b, 'tcx> {
+ fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
+ NestedVisitorMap::None
+ }
+
+ fn visit_nested_body(&mut self, body: hir::BodyId) {
+ let body = self.ecx.tcx.map.body(body);
+ body.encode(self.ecx).unwrap();
+ self.count += 1;
+
+ self.visit_body(body);
+ }
+}
+
+/// Decodes an item's body from its AST in the cdata's metadata and adds it to the
/// ast-map.
-pub fn decode_inlined_item<'a, 'tcx>(cdata: &CrateMetadata,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- ast: Ast<'tcx>,
- orig_did: DefId)
- -> &'tcx InlinedItem {
- debug!("> Decoding inlined fn: {:?}", tcx.item_path_str(orig_did));
+pub fn decode_body<'a, 'tcx>(cdata: &CrateMetadata,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId,
+ ast: Ast<'tcx>)
+ -> &'tcx hir::Body {
+ debug!("> Decoding inlined fn: {}", tcx.item_path_str(def_id));
let cnt = ast.id_range.max.as_usize() - ast.id_range.min.as_usize();
let start = tcx.sess.reserve_node_ids(cnt);
max: ast::NodeId::new(start.as_usize() + cnt),
}];
- let ii = ast.item.decode((cdata, tcx, id_ranges));
- let item_node_id = tcx.sess.next_node_id();
- let ii = ast_map::map_decoded_item(&tcx.map,
- ii,
- item_node_id);
-
for (id, entry) in ast.side_tables.decode((cdata, tcx, id_ranges)) {
match entry {
TableEntry::TypeRelativeDef(def) => {
TableEntry::Adjustment(adj) => {
tcx.tables.borrow_mut().adjustments.insert(id, adj);
}
- TableEntry::ConstQualif(qualif) => {
- tcx.const_qualif_map.borrow_mut().insert(id, qualif);
- }
}
}
- ii
+ let body = ast.body.decode((cdata, tcx, id_ranges));
+ ast_map::map_decoded_body(&tcx.map, def_id, body, tcx.sess.next_node_id())
}
config::CrateTypeProcMacro |
config::CrateTypeCdylib |
config::CrateTypeStaticlib => need_lib_alloc = true,
- config::CrateTypeRlib |
- config::CrateTypeMetadata => {}
+ config::CrateTypeRlib => {}
}
}
if !need_lib_alloc && !need_exe_alloc { return }
pub dllimport_foreign_items: FxHashSet<DefIndex>,
}
-pub struct CachedInlinedItem {
- /// The NodeId of the RootInlinedParent HIR map entry
- pub inlined_root: ast::NodeId,
- /// The local NodeId of the inlined entity
- pub item_id: ast::NodeId,
-}
-
pub struct CStore {
pub dep_graph: DepGraph,
metas: RefCell<FxHashMap<CrateNum, Rc<CrateMetadata>>>,
used_link_args: RefCell<Vec<String>>,
statically_included_foreign_items: RefCell<FxHashSet<DefIndex>>,
pub dllimport_foreign_items: RefCell<FxHashSet<DefIndex>>,
- pub inlined_item_cache: RefCell<DefIdMap<Option<CachedInlinedItem>>>,
- pub defid_for_inlined_node: RefCell<NodeMap<DefId>>,
+ pub inlined_item_cache: RefCell<DefIdMap<Option<ast::NodeId>>>,
pub visible_parent_map: RefCell<DefIdMap<DefId>>,
}
dllimport_foreign_items: RefCell::new(FxHashSet()),
visible_parent_map: RefCell::new(FxHashMap()),
inlined_item_cache: RefCell::new(FxHashMap()),
- defid_for_inlined_node: RefCell::new(FxHashMap()),
}
}
use locator;
use schema;
-use rustc::middle::cstore::{InlinedItem, CrateStore, CrateSource, LibSource, DepKind, ExternCrate};
+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_back::target::Target;
use rustc::hir;
+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));
fn fn_arg_names(&self, did: DefId) -> Vec<ast::Name>
{
- self.dep_graph.read(DepNode::MetaData(did));
+ // FIXME(#38501) We've skipped a `read` on the `HirBody` of
+ // a `fn` when encoding, so the dep-tracking wouldn't work.
+ // This is only used by rustdoc anyway, which shouldn't have
+ // incremental recompilation ever enabled.
+ assert!(!self.dep_graph.is_fully_enabled());
self.get_crate_data(did.krate).get_fn_arg_names(did.index)
}
self.get_crate_data(def_id.krate).get_trait_of_item(def_id.index)
}
- fn associated_item<'a>(&self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, def: DefId)
- -> Option<ty::AssociatedItem>
+ fn associated_item(&self, def: DefId) -> Option<ty::AssociatedItem>
{
self.dep_graph.read(DepNode::MetaData(def));
self.get_crate_data(def.krate).get_associated_item(def.index)
})
}
- fn maybe_get_item_ast<'a>(&'tcx self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- def_id: DefId)
- -> Option<(&'tcx InlinedItem, ast::NodeId)>
+ fn maybe_get_item_body<'a>(&'tcx self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ def_id: DefId)
+ -> Option<&'tcx hir::Body>
{
self.dep_graph.read(DepNode::MetaData(def_id));
- match self.inlined_item_cache.borrow().get(&def_id) {
- Some(&None) => {
- return None; // Not inlinable
- }
- Some(&Some(ref cached_inlined_item)) => {
+ if let Some(&cached) = self.inlined_item_cache.borrow().get(&def_id) {
+ return cached.map(|root_id| {
// Already inline
- debug!("maybe_get_item_ast({}): already inline as node id {}",
- tcx.item_path_str(def_id), cached_inlined_item.item_id);
- return Some((tcx.map.expect_inlined_item(cached_inlined_item.inlined_root),
- cached_inlined_item.item_id));
- }
- None => {
- // Not seen yet
- }
+ debug!("maybe_get_item_body({}): already inline", tcx.item_path_str(def_id));
+ tcx.map.expect_inlined_body(root_id)
+ });
}
- debug!("maybe_get_item_ast({}): inlining item", tcx.item_path_str(def_id));
+ debug!("maybe_get_item_body({}): inlining item", tcx.item_path_str(def_id));
- let inlined = self.get_crate_data(def_id.krate).maybe_get_item_ast(tcx, def_id.index);
-
- let cache_inlined_item = |original_def_id, inlined_item_id, inlined_root_node_id| {
- let cache_entry = cstore::CachedInlinedItem {
- inlined_root: inlined_root_node_id,
- item_id: inlined_item_id,
- };
- self.inlined_item_cache
- .borrow_mut()
- .insert(original_def_id, Some(cache_entry));
- self.defid_for_inlined_node
- .borrow_mut()
- .insert(inlined_item_id, original_def_id);
- };
-
- let find_inlined_item_root = |inlined_item_id| {
- let mut node = inlined_item_id;
-
- // If we can't find the inline root after a thousand hops, we can
- // be pretty sure there's something wrong with the HIR map.
- for _ in 0 .. 1000 {
- let parent_node = tcx.map.get_parent_node(node);
- if parent_node == node {
- return node;
- }
- node = parent_node;
- }
- bug!("cycle in HIR map parent chain")
- };
+ let inlined = self.get_crate_data(def_id.krate).maybe_get_item_body(tcx, def_id.index);
- match inlined {
- None => {
- self.inlined_item_cache
- .borrow_mut()
- .insert(def_id, None);
- }
- Some(&InlinedItem { ref body, .. }) => {
- let inlined_root_node_id = find_inlined_item_root(body.id);
- cache_inlined_item(def_id, inlined_root_node_id, inlined_root_node_id);
- }
- }
+ self.inlined_item_cache.borrow_mut().insert(def_id, inlined.map(|body| {
+ let root_id = tcx.map.get_parent_node(body.value.id);
+ assert_eq!(tcx.map.get_parent_node(root_id), root_id);
+ root_id
+ }));
- // We can be sure to hit the cache now
- return self.maybe_get_item_ast(tcx, def_id);
+ inlined
}
- fn local_node_for_inlined_defid(&'tcx self, def_id: DefId) -> Option<ast::NodeId> {
- assert!(!def_id.is_local());
- match self.inlined_item_cache.borrow().get(&def_id) {
- Some(&Some(ref cached_inlined_item)) => {
- Some(cached_inlined_item.item_id)
- }
- Some(&None) => {
- None
- }
- _ => {
- bug!("Trying to lookup inlined NodeId for unexpected item");
- }
- }
+ fn item_body_nested_bodies(&self, def: DefId) -> BTreeMap<hir::BodyId, hir::Body> {
+ self.dep_graph.read(DepNode::MetaData(def));
+ self.get_crate_data(def.krate).item_body_nested_bodies(def.index)
}
- fn defid_for_inlined_node(&'tcx self, node_id: ast::NodeId) -> Option<DefId> {
- self.defid_for_inlined_node.borrow().get(&node_id).map(|x| *x)
+ fn const_is_rvalue_promotable_to_static(&self, def: DefId) -> bool {
+ self.dep_graph.read(DepNode::MetaData(def));
+ 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> {
// Decoding metadata from a single crate's metadata
-use astencode::decode_inlined_item;
+use astencode::decode_body;
use cstore::{self, CrateMetadata, MetadataBlob, NativeLibrary};
use schema::*;
use rustc::hir;
use rustc::hir::intravisit::IdRange;
-use rustc::middle::cstore::{InlinedItem, LinkagePreference};
+use rustc::middle::cstore::LinkagePreference;
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 std::borrow::Cow;
use std::cell::Ref;
+use std::collections::BTreeMap;
use std::io;
use std::mem;
use std::str;
ty::FieldDef {
did: self.local_def_id(index),
name: self.item_name(index),
- vis: f.visibility
+ vis: f.visibility.decode(self)
}
}).collect(),
disr_val: ConstInt::Infer(data.disr),
pub fn get_visibility(&self, id: DefIndex) -> ty::Visibility {
match self.is_proc_macro(id) {
true => ty::Visibility::Public,
- false => self.entry(id).visibility,
+ false => self.entry(id).visibility.decode(self),
}
}
}
}
- pub fn maybe_get_item_ast(&self,
- tcx: TyCtxt<'a, 'tcx, 'tcx>,
- id: DefIndex)
- -> Option<&'tcx InlinedItem> {
- debug!("Looking up item: {:?}", id);
+ pub fn maybe_get_item_body(&self,
+ tcx: TyCtxt<'a, 'tcx, 'tcx>,
+ id: DefIndex)
+ -> Option<&'tcx hir::Body> {
if self.is_proc_macro(id) { return None; }
- let item_doc = self.entry(id);
- let item_did = self.local_def_id(id);
- item_doc.ast.map(|ast| {
- let ast = ast.decode(self);
- decode_inlined_item(self, tcx, ast, item_did)
+ self.entry(id).ast.map(|ast| {
+ decode_body(self, tcx, self.local_def_id(id), ast.decode(self))
})
}
+ 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))
+ }).collect()
+ }
+
+ pub fn const_is_rvalue_promotable_to_static(&self, id: DefIndex) -> bool {
+ self.entry(id).ast.expect("const item missing `ast`")
+ .decode(self).rvalue_promotable_to_static
+ }
+
pub fn is_item_mir_available(&self, id: DefIndex) -> bool {
!self.is_proc_macro(id) &&
self.maybe_entry(id).and_then(|item| item.decode(self).mir).is_some()
ty::AssociatedItem {
name: name,
kind: ty::AssociatedKind::Const,
- vis: item.visibility,
+ vis: item.visibility.decode(self),
defaultness: container.defaultness(),
def_id: self.local_def_id(id),
container: container.with_def_id(parent),
ty::AssociatedItem {
name: name,
kind: ty::AssociatedKind::Method,
- vis: item.visibility,
+ vis: item.visibility.decode(self),
defaultness: data.container.defaultness(),
def_id: self.local_def_id(id),
container: data.container.with_def_id(parent),
ty::AssociatedItem {
name: name,
kind: ty::AssociatedKind::Type,
- vis: item.visibility,
+ vis: item.visibility.decode(self),
defaultness: container.defaultness(),
def_id: self.local_def_id(id),
container: container.with_def_id(parent),
let filter = match filter.map(|def_id| self.reverse_translate_def_id(def_id)) {
Some(Some(def_id)) => Some((def_id.krate.as_u32(), def_id.index)),
Some(None) => return,
+ None if self.proc_macros.is_some() => return,
None => None,
};
Please specify a valid "kind" value, from one of the following:
- * static
- * dylib
- * framework
+* static
+* dylib
+* framework
"##,
use index::Index;
use schema::*;
-use rustc::middle::cstore::{InlinedItemRef, LinkMeta};
-use rustc::middle::cstore::{LinkagePreference, NativeLibrary};
+use rustc::middle::cstore::{LinkMeta, LinkagePreference, NativeLibrary};
use rustc::hir::def;
use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefIndex, DefId};
use rustc::hir::map::definitions::DefPathTable;
use std::rc::Rc;
use std::u32;
use syntax::ast::{self, CRATE_NODE_ID};
+use syntax::codemap::Spanned;
use syntax::attr;
use syntax::symbol::Symbol;
use syntax_pos;
Entry {
kind: EntryKind::Variant(self.lazy(&data)),
- visibility: enum_vis.simplify(),
+ visibility: self.lazy(&ty::Visibility::from_hir(enum_vis, enum_id, tcx)),
span: self.lazy(&tcx.def_span(def_id)),
attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
children: self.lazy_seq(variant.fields.iter().map(|f| {
Entry {
kind: EntryKind::Mod(self.lazy(&data)),
- visibility: vis.simplify(),
+ visibility: self.lazy(&ty::Visibility::from_hir(vis, id, tcx)),
span: self.lazy(&md.inner),
attributes: self.encode_attributes(attrs),
children: self.lazy_seq(md.item_ids.iter().map(|item_id| {
}
}
-trait Visibility {
- fn simplify(&self) -> ty::Visibility;
-}
-
-impl Visibility for hir::Visibility {
- fn simplify(&self) -> ty::Visibility {
- if *self == hir::Public {
- ty::Visibility::Public
- } else {
- ty::Visibility::PrivateExternal
- }
- }
-}
-
-impl Visibility for ty::Visibility {
- fn simplify(&self) -> ty::Visibility {
- if *self == ty::Visibility::Public {
- ty::Visibility::Public
- } else {
- ty::Visibility::PrivateExternal
- }
- }
-}
-
impl<'a, 'b, 'tcx> IndexBuilder<'a, 'b, 'tcx> {
fn encode_fields(&mut self, adt_def_id: DefId) {
let def = self.tcx.lookup_adt_def(adt_def_id);
Entry {
kind: EntryKind::Field,
- visibility: field.vis.simplify(),
+ visibility: self.lazy(&field.vis),
span: self.lazy(&tcx.def_span(def_id)),
attributes: self.encode_attributes(&variant_data.fields()[field_index].attrs),
children: LazySeq::empty(),
Entry {
kind: EntryKind::Struct(self.lazy(&data)),
- visibility: struct_vis.simplify(),
+ visibility: self.lazy(&ty::Visibility::from_hir(struct_vis, struct_id, tcx)),
span: self.lazy(&tcx.def_span(def_id)),
attributes: LazySeq::empty(),
children: LazySeq::empty(),
let kind = match trait_item.kind {
ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
ty::AssociatedKind::Method => {
- let fn_data = if let hir::MethodTraitItem(ref sig, _) = ast_item.node {
+ let fn_data = if let hir::TraitItemKind::Method(_, ref m) = ast_item.node {
+ let arg_names = match *m {
+ hir::TraitMethod::Required(ref names) => {
+ self.encode_fn_arg_names(names)
+ }
+ hir::TraitMethod::Provided(body) => {
+ self.encode_fn_arg_names_for_body(body)
+ }
+ };
FnData {
constness: hir::Constness::NotConst,
- arg_names: self.encode_fn_arg_names(&sig.decl),
+ arg_names: arg_names
}
} else {
bug!()
Entry {
kind: kind,
- visibility: trait_item.vis.simplify(),
+ visibility: self.lazy(&trait_item.vis),
span: self.lazy(&ast_item.span),
attributes: self.encode_attributes(&ast_item.attrs),
children: LazySeq::empty(),
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: if let hir::ConstTraitItem(_, Some(_)) = ast_item.node {
- // We only save the HIR for associated consts with bodies
- // (InlinedItemRef::from_trait_item panics otherwise)
- let trait_def_id = trait_item.container.id();
- Some(self.encode_inlined_item(
- InlinedItemRef::from_trait_item(trait_def_id, ast_item, tcx)
- ))
+ ast: if let hir::TraitItemKind::Const(_, Some(body)) = ast_item.node {
+ Some(self.encode_body(body))
} else {
None
},
}
fn encode_info_for_impl_item(&mut self, def_id: DefId) -> Entry<'tcx> {
- let tcx = self.tcx;
-
let node_id = self.tcx.map.as_local_node_id(def_id).unwrap();
let ast_item = self.tcx.map.expect_impl_item(node_id);
let impl_item = self.tcx.associated_item(def_id);
- let impl_def_id = impl_item.container.id();
let container = match impl_item.defaultness {
hir::Defaultness::Default { has_value: true } => AssociatedContainer::ImplDefault,
let kind = match impl_item.kind {
ty::AssociatedKind::Const => EntryKind::AssociatedConst(container),
ty::AssociatedKind::Method => {
- let fn_data = if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+ let fn_data = if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
FnData {
constness: sig.constness,
- arg_names: self.encode_fn_arg_names(&sig.decl),
+ arg_names: self.encode_fn_arg_names_for_body(body),
}
} else {
bug!()
ty::AssociatedKind::Type => EntryKind::AssociatedType(container)
};
- let (ast, mir) = if impl_item.kind == ty::AssociatedKind::Const {
- (true, true)
- } else if let hir::ImplItemKind::Method(ref sig, _) = ast_item.node {
+ let (ast, mir) = if let hir::ImplItemKind::Const(_, body) = ast_item.node {
+ (Some(body), true)
+ } else if let hir::ImplItemKind::Method(ref sig, body) = ast_item.node {
let generics = self.tcx.item_generics(def_id);
let types = generics.parent_types as usize + generics.types.len();
let needs_inline = types > 0 || attr::requests_inline(&ast_item.attrs);
let is_const_fn = sig.constness == hir::Constness::Const;
+ let ast = if is_const_fn { Some(body) } else { None };
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
- (is_const_fn, needs_inline || is_const_fn || always_encode_mir)
+ (ast, needs_inline || is_const_fn || always_encode_mir)
} else {
- (false, false)
+ (None, false)
};
Entry {
kind: kind,
- visibility: impl_item.vis.simplify(),
+ visibility: self.lazy(&impl_item.vis),
span: self.lazy(&ast_item.span),
attributes: self.encode_attributes(&ast_item.attrs),
children: LazySeq::empty(),
generics: Some(self.encode_generics(def_id)),
predicates: Some(self.encode_predicates(def_id)),
- ast: if ast {
- Some(self.encode_inlined_item(
- InlinedItemRef::from_impl_item(impl_def_id, ast_item, tcx)
- ))
- } else {
- None
- },
+ ast: ast.map(|body| self.encode_body(body)),
mir: if mir { self.encode_mir(def_id) } else { None },
}
}
- fn encode_fn_arg_names(&mut self, decl: &hir::FnDecl) -> LazySeq<ast::Name> {
- self.lazy_seq(decl.inputs.iter().map(|arg| {
- if let PatKind::Binding(_, _, ref path1, _) = arg.pat.node {
- path1.node
- } else {
- Symbol::intern("")
+ fn encode_fn_arg_names_for_body(&mut self, body_id: hir::BodyId)
+ -> LazySeq<ast::Name> {
+ let _ignore = self.tcx.dep_graph.in_ignore();
+ let body = self.tcx.map.body(body_id);
+ self.lazy_seq(body.arguments.iter().map(|arg| {
+ match arg.pat.node {
+ PatKind::Binding(_, _, name, _) => name.node,
+ _ => Symbol::intern("")
}
}))
}
+ fn encode_fn_arg_names(&mut self, names: &[Spanned<ast::Name>])
+ -> LazySeq<ast::Name> {
+ self.lazy_seq(names.iter().map(|name| name.node))
+ }
+
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()))
}
hir::ItemStatic(_, hir::MutMutable, _) => EntryKind::MutStatic,
hir::ItemStatic(_, hir::MutImmutable, _) => EntryKind::ImmStatic,
hir::ItemConst(..) => EntryKind::Const,
- hir::ItemFn(ref decl, _, constness, ..) => {
+ hir::ItemFn(_, _, constness, .., body) => {
let data = FnData {
constness: constness,
- arg_names: self.encode_fn_arg_names(&decl),
+ arg_names: self.encode_fn_arg_names_for_body(body),
};
EntryKind::Fn(self.lazy(&data))
Entry {
kind: kind,
- visibility: item.vis.simplify(),
+ visibility: self.lazy(&ty::Visibility::from_hir(&item.vis, item.id, tcx)),
span: self.lazy(&item.span),
attributes: self.encode_attributes(&item.attrs),
children: match item.node {
},
ast: match item.node {
- hir::ItemConst(..) |
- hir::ItemFn(_, _, hir::Constness::Const, ..) => {
- Some(self.encode_inlined_item(
- InlinedItemRef::from_item(def_id, item, tcx)
- ))
+ hir::ItemConst(_, body) |
+ hir::ItemFn(_, _, hir::Constness::Const, _, _, body) => {
+ Some(self.encode_body(body))
}
_ => None,
},
mir: match item.node {
- hir::ItemStatic(..) |
+ hir::ItemStatic(..) if self.tcx.sess.opts.debugging_opts.always_encode_mir => {
+ self.encode_mir(def_id)
+ }
hir::ItemConst(..) => self.encode_mir(def_id),
hir::ItemFn(_, _, constness, _, ref generics, _) => {
let tps_len = generics.ty_params.len();
kind: EntryKind::MacroDef(self.lazy(&MacroDef {
body: ::syntax::print::pprust::tts_to_string(¯o_def.body)
})),
- visibility: ty::Visibility::Public,
+ visibility: self.lazy(&ty::Visibility::Public),
span: self.lazy(¯o_def.span),
attributes: self.encode_attributes(¯o_def.attrs),
debug!("writing foreign item {}", tcx.node_path_str(nitem.id));
let kind = match nitem.node {
- hir::ForeignItemFn(ref fndecl, _) => {
+ hir::ForeignItemFn(_, ref names, _) => {
let data = FnData {
constness: hir::Constness::NotConst,
- arg_names: self.encode_fn_arg_names(&fndecl),
+ arg_names: self.encode_fn_arg_names(names),
};
EntryKind::ForeignFn(self.lazy(&data))
}
Entry {
kind: kind,
- visibility: nitem.vis.simplify(),
+ visibility: self.lazy(&ty::Visibility::from_hir(&nitem.vis, nitem.id, tcx)),
span: self.lazy(&nitem.span),
attributes: self.encode_attributes(&nitem.attrs),
children: LazySeq::empty(),
let tcx = self.tcx;
Entry {
kind: EntryKind::Type,
- visibility: ty::Visibility::Public,
+ visibility: self.lazy(&ty::Visibility::Public),
span: self.lazy(&tcx.def_span(def_id)),
attributes: LazySeq::empty(),
children: LazySeq::empty(),
Entry {
kind: EntryKind::Closure(self.lazy(&data)),
- visibility: ty::Visibility::Public,
+ visibility: self.lazy(&ty::Visibility::Public),
span: self.lazy(&tcx.def_span(def_id)),
attributes: self.encode_attributes(&tcx.get_attrs(def_id)),
children: LazySeq::empty(),
}
}
+ fn visit_trait_item(&mut self, _trait_item: &'v hir::TraitItem) {}
+
fn visit_impl_item(&mut self, _impl_item: &'v hir::ImplItem) {
// handled in `visit_item` above
}
#[derive(RustcEncodable, RustcDecodable)]
pub struct Entry<'tcx> {
pub kind: EntryKind<'tcx>,
- pub visibility: ty::Visibility,
+ pub visibility: Lazy<ty::Visibility>,
pub span: Lazy<Span>,
pub attributes: LazySeq<ast::Attribute>,
pub children: LazySeq<DefIndex>,
name: Some(name),
source_info: Some(source_info),
});
- let extent = self.extent_of_innermost_scope();
+ let extent = self.hir.tcx().region_maps.var_scope(var_id);
self.schedule_drop(source_info.span, extent, &Lvalue::Local(var), var_ty);
self.var_indices.insert(var_id, var);
arguments: A,
abi: Abi,
return_ty: Ty<'gcx>,
- ast_body: &'gcx hir::Expr)
+ body: &'gcx hir::Body)
-> Mir<'tcx>
where A: Iterator<Item=(Ty<'gcx>, Option<&'gcx hir::Pat>)>
{
let span = tcx.map.span(fn_id);
let mut builder = Builder::new(hir, span, arguments.len(), return_ty);
- let body_id = ast_body.id;
let call_site_extent =
tcx.region_maps.lookup_code_extent(
- CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body_id });
+ CodeExtentData::CallSiteScope { fn_id: fn_id, body_id: body.value.id });
let arg_extent =
tcx.region_maps.lookup_code_extent(
- CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body_id });
+ CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.value.id });
let mut block = START_BLOCK;
unpack!(block = builder.in_scope(call_site_extent, block, |builder| {
unpack!(block = builder.in_scope(arg_extent, block, |builder| {
- builder.args_and_body(block, &arguments, arg_extent, ast_body)
+ builder.args_and_body(block, &arguments, arg_extent, &body.value)
}));
// Attribute epilogue to function's closing brace
let fn_end = Span { lo: span.hi, ..span };
pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
item_id: ast::NodeId,
- ast_expr: &'tcx hir::Expr)
+ body_id: hir::BodyId)
-> Mir<'tcx> {
let tcx = hir.tcx();
+ let ast_expr = &tcx.map.body(body_id).value;
let ty = tcx.tables().expr_ty_adjusted(ast_expr);
let span = tcx.map.span(item_id);
let mut builder = Builder::new(hir, span, 0, ty);
f: F)
where F: FnOnce(&mut Builder<'a, 'gcx, 'tcx>)
{
- let extent = self.extent_of_innermost_scope();
+ let extent = self.scopes.last().map(|scope| scope.extent).unwrap();
let loop_scope = LoopScope {
extent: extent.clone(),
continue_block: loop_block,
}
}
- pub fn extent_of_innermost_scope(&self) -> CodeExtent {
- self.scopes.last().map(|scope| scope.extent).unwrap()
- }
-
/// Returns the extent of the scope which should be exited by a
/// return.
pub fn extent_of_return_scope(&self) -> CodeExtent {
}
// Now comes the rote stuff:
- hir::ExprRepeat(ref v, ref c) => {
+ hir::ExprRepeat(ref v, c) => {
+ let c = &cx.tcx.map.body(c).value;
ExprKind::Repeat {
value: v.to_ref(),
count: TypedConstVal {
ConstVal::Integral(ConstInt::Usize(u)) => u,
other => bug!("constant evaluation of repeat count yielded {:?}", other),
},
- },
+ }
}
}
hir::ExprRet(ref v) => ExprKind::Return { value: v.to_ref() },
let body_id = match cx.tcx.map.find(closure_expr_id) {
Some(map::NodeExpr(expr)) => {
match expr.node {
- hir::ExprClosure(.., body_id, _) => body_id.node_id(),
+ hir::ExprClosure(.., body, _) => body.node_id,
_ => {
span_bug!(expr.span, "closure expr is not a closure expr");
}
#![feature(associated_consts)]
#![feature(box_patterns)]
-#![cfg_attr(stage0, feature(item_like_imports))]
#![feature(rustc_diagnostic_macros)]
#![feature(rustc_private)]
#![feature(staged_api)]
}
impl<'a, 'gcx> BuildMir<'a, 'gcx> {
- fn build_const_integer(&mut self, expr: &'gcx hir::Expr) {
+ fn build_const_integer(&mut self, body: hir::BodyId) {
+ let body = self.tcx.map.body(body);
// FIXME(eddyb) Closures should have separate
// function definition IDs and expression IDs.
// Type-checking should not let closures get
// this far in an integer constant position.
- if let hir::ExprClosure(..) = expr.node {
+ if let hir::ExprClosure(..) = body.value.node {
return;
}
- self.cx(MirSource::Const(expr.id)).build(|cx| {
- build::construct_const(cx, expr.id, expr)
+ self.cx(MirSource::Const(body.value.id)).build(|cx| {
+ build::construct_const(cx, body.value.id, body.id())
});
}
}
// Const and static items.
fn visit_item(&mut self, item: &'tcx hir::Item) {
match item.node {
- hir::ItemConst(_, ref expr) => {
+ hir::ItemConst(_, expr) => {
self.cx(MirSource::Const(item.id)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
}
- hir::ItemStatic(_, m, ref expr) => {
+ hir::ItemStatic(_, m, expr) => {
self.cx(MirSource::Static(item.id, m)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
// Trait associated const defaults.
fn visit_trait_item(&mut self, item: &'tcx hir::TraitItem) {
- if let hir::ConstTraitItem(_, Some(ref expr)) = item.node {
+ if let hir::TraitItemKind::Const(_, Some(expr)) = item.node {
self.cx(MirSource::Const(item.id)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
// Impl associated const.
fn visit_impl_item(&mut self, item: &'tcx hir::ImplItem) {
- if let hir::ImplItemKind::Const(_, ref expr) = item.node {
+ if let hir::ImplItemKind::Const(_, expr) = item.node {
self.cx(MirSource::Const(item.id)).build(|cx| {
build::construct_const(cx, item.id, expr)
});
// Repeat counts, i.e. [expr; constant].
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
- if let hir::ExprRepeat(_, ref count) = expr.node {
+ if let hir::ExprRepeat(_, count) = expr.node {
self.build_const_integer(count);
}
intravisit::walk_expr(self, expr);
// Array lengths, i.e. [T; constant].
fn visit_ty(&mut self, ty: &'tcx hir::Ty) {
- if let hir::TyArray(_, ref length) = ty.node {
+ if let hir::TyArray(_, length) = ty.node {
self.build_const_integer(length);
}
intravisit::walk_ty(self, ty);
// Enum variant discriminant values.
fn visit_variant(&mut self, v: &'tcx hir::Variant,
g: &'tcx hir::Generics, item_id: ast::NodeId) {
- if let Some(ref expr) = v.node.disr_expr {
+ if let Some(expr) = v.node.disr_expr {
self.build_const_integer(expr);
}
intravisit::walk_variant(self, v, g, item_id);
fn visit_fn(&mut self,
fk: FnKind<'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
span: Span,
id: ast::NodeId) {
// fetch the fully liberated fn signature (that is, all bound
};
let (abi, implicit_argument) = if let FnKind::Closure(..) = fk {
- (Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id()), None)))
+ (Abi::Rust, Some((closure_self_ty(self.tcx, id, body_id.node_id), None)))
} else {
let def_id = self.tcx.map.local_def_id(id);
(self.tcx.item_type(def_id).fn_abi(), None)
};
+ let body = self.tcx.map.body(body_id);
let explicit_arguments =
- decl.inputs
+ body.arguments
.iter()
.enumerate()
.map(|(index, arg)| {
(fn_sig.inputs()[index], Some(&*arg.pat))
});
- let body = self.tcx.map.expr(body_id);
-
let arguments = implicit_argument.into_iter().chain(explicit_arguments);
self.cx(MirSource::Fn(id)).build(|cx| {
build::construct_fn(cx, id, arguments, abi, fn_sig.output(), body)
}
fn visit_path(&mut self, path: &'a Path, id: NodeId) {
- if path.global && path.segments.len() > 0 {
- let ident = path.segments[0].identifier;
+ if path.segments.len() >= 2 && path.is_global() {
+ let ident = path.segments[1].identifier;
if token::Ident(ident).is_path_segment_keyword() {
self.session.add_lint(lint::builtin::SUPER_OR_SELF_IN_GLOBAL_PATH,
id,
use rustc::dep_graph::DepNode;
use rustc::ty::cast::CastKind;
-use rustc_const_eval::{ConstEvalErr, lookup_const_fn_by_id, compare_lit_exprs};
-use rustc_const_eval::{ConstFnNode, eval_const_expr_partial, lookup_const_by_id};
+use rustc_const_eval::{ConstEvalErr, compare_lit_exprs};
+use rustc_const_eval::{eval_const_expr_partial};
use rustc_const_eval::ErrKind::{IndexOpFeatureGated, UnimplementedConstVal, MiscCatchAll, Math};
use rustc_const_eval::ErrKind::{ErroneousReferencedConstant, MiscBinaryOp, NonConstPath};
use rustc_const_eval::ErrKind::UnresolvedPath;
use rustc_const_math::{ConstMathErr, Op};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
+use rustc::hir::map::blocks::FnLikeNode;
use rustc::middle::expr_use_visitor as euv;
use rustc::middle::mem_categorization as mc;
use rustc::middle::mem_categorization::Categorization;
+use rustc::mir::transform::MirSource;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::traits::Reveal;
use rustc::util::common::ErrorReported;
-use rustc::util::nodemap::NodeMap;
-use rustc::middle::const_qualif::ConstQualif;
+use rustc::util::nodemap::NodeSet;
use rustc::lint::builtin::CONST_ERR;
use rustc::hir::{self, PatKind};
use syntax::ast;
use syntax_pos::Span;
-use rustc::hir::intravisit::{self, FnKind, Visitor, NestedVisitorMap};
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use std::collections::hash_map::Entry;
use std::cmp::Ordering;
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-enum Mode {
- Const,
- ConstFn,
- Static,
- StaticMut,
-
- // An expression that occurs outside of any constant context
- // (i.e. `const`, `static`, array lengths, etc.). The value
- // can be variable at runtime, but will be promotable to
- // static memory if we can prove it is actually constant.
- Var,
-}
+use std::mem;
struct CheckCrateVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- mode: Mode,
- qualif: ConstQualif,
- rvalue_borrows: NodeMap<hir::Mutability>,
+ in_fn: bool,
+ promotable: bool,
+ mut_rvalue_borrows: NodeSet,
+ param_env: ty::ParameterEnvironment<'tcx>,
}
impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> {
- fn with_mode<F, R>(&mut self, mode: Mode, f: F) -> R
- where F: FnOnce(&mut CheckCrateVisitor<'a, 'gcx>) -> R
- {
- let (old_mode, old_qualif) = (self.mode, self.qualif);
- self.mode = mode;
- self.qualif = ConstQualif::empty();
- let r = f(self);
- self.mode = old_mode;
- self.qualif = old_qualif;
- r
- }
-
- fn with_euv<F, R>(&mut self, item_id: Option<ast::NodeId>, f: F) -> R
- where F: for<'b, 'tcx> FnOnce(&mut euv::ExprUseVisitor<'b, 'gcx, 'tcx>) -> R
- {
- let param_env = match item_id {
- Some(item_id) => ty::ParameterEnvironment::for_item(self.tcx, item_id),
- None => self.tcx.empty_parameter_environment(),
- };
-
- self.tcx
- .infer_ctxt(None, Some(param_env), Reveal::NotSpecializable)
- .enter(|infcx| f(&mut euv::ExprUseVisitor::new(self, &infcx)))
- }
-
- fn global_expr(&mut self, mode: Mode, expr: &'gcx hir::Expr) -> ConstQualif {
- assert!(mode != Mode::Var);
- match self.tcx.const_qualif_map.borrow_mut().entry(expr.id) {
- Entry::Occupied(entry) => return *entry.get(),
- Entry::Vacant(entry) => {
- // Prevent infinite recursion on re-entry.
- entry.insert(ConstQualif::empty());
- }
- }
+ fn check_const_eval(&self, expr: &'gcx hir::Expr) {
if let Err(err) = eval_const_expr_partial(self.tcx, expr, ExprTypeChecked, None) {
match err.kind {
UnimplementedConstVal(_) => {}
}
}
}
- self.with_mode(mode, |this| {
- this.with_euv(None, |euv| euv.consume_expr(expr));
- this.visit_expr(expr);
- this.qualif
- })
}
- fn fn_like(&mut self,
- fk: FnKind<'gcx>,
- fd: &'gcx hir::FnDecl,
- b: hir::ExprId,
- s: Span,
- fn_id: ast::NodeId)
- -> ConstQualif {
- match self.tcx.const_qualif_map.borrow_mut().entry(fn_id) {
- Entry::Occupied(entry) => return *entry.get(),
- Entry::Vacant(entry) => {
- // Prevent infinite recursion on re-entry.
- entry.insert(ConstQualif::empty());
- }
+ // Adds the worst effect out of all the values of one type.
+ fn add_type(&mut self, ty: Ty<'gcx>) {
+ if ty.type_contents(self.tcx).interior_unsafe() {
+ self.promotable = false;
}
- let mode = match fk {
- FnKind::ItemFn(_, _, _, hir::Constness::Const, ..)
- => Mode::ConstFn,
- FnKind::Method(_, m, ..) => {
- if m.constness == hir::Constness::Const {
- Mode::ConstFn
- } else {
- Mode::Var
- }
- }
- _ => Mode::Var,
- };
-
- let qualif = self.with_mode(mode, |this| {
- let body = this.tcx.map.expr(b);
- this.with_euv(Some(fn_id), |euv| euv.walk_fn(fd, body));
- intravisit::walk_fn(this, fk, fd, b, s, fn_id);
- this.qualif
- });
-
- // Keep only bits that aren't affected by function body (NON_ZERO_SIZED),
- // and bits that don't change semantics, just optimizations (PREFER_IN_PLACE).
- let qualif = qualif & (ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
-
- self.tcx.const_qualif_map.borrow_mut().insert(fn_id, qualif);
- qualif
- }
-
- fn add_qualif(&mut self, qualif: ConstQualif) {
- self.qualif = self.qualif | qualif;
- }
-
- /// Returns true if the call is to a const fn or method.
- fn handle_const_fn_call(&mut self, _expr: &hir::Expr, def_id: DefId, ret_ty: Ty<'gcx>) -> bool {
- match lookup_const_fn_by_id(self.tcx, def_id) {
- Some(ConstFnNode::Local(fn_like)) => {
- let qualif = self.fn_like(fn_like.kind(),
- fn_like.decl(),
- fn_like.body(),
- fn_like.span(),
- fn_like.id());
-
- self.add_qualif(qualif);
-
- if ret_ty.type_contents(self.tcx).interior_unsafe() {
- self.add_qualif(ConstQualif::MUTABLE_MEM);
- }
-
- true
- },
- Some(ConstFnNode::Inlined(ii)) => {
- let node_id = ii.body.id;
-
- let qualif = match self.tcx.const_qualif_map.borrow_mut().entry(node_id) {
- Entry::Occupied(entry) => *entry.get(),
- _ => bug!("const qualif entry missing for inlined item")
- };
-
- self.add_qualif(qualif);
-
- if ret_ty.type_contents(self.tcx).interior_unsafe() {
- self.add_qualif(ConstQualif::MUTABLE_MEM);
- }
-
- true
- },
- None => false
+ if self.tcx.type_needs_drop_given_env(ty, &self.param_env) {
+ self.promotable = false;
}
}
- fn record_borrow(&mut self, id: ast::NodeId, mutbl: hir::Mutability) {
- match self.rvalue_borrows.entry(id) {
- Entry::Occupied(mut entry) => {
- // Merge the two borrows, taking the most demanding
- // one, mutability-wise.
- if mutbl == hir::MutMutable {
- entry.insert(mutbl);
- }
- }
- Entry::Vacant(entry) => {
- entry.insert(mutbl);
- }
- }
+ fn handle_const_fn_call(&mut self, def_id: DefId, ret_ty: Ty<'gcx>) {
+ self.add_type(ret_ty);
+
+ self.promotable &= if let Some(fn_id) = self.tcx.map.as_local_node_id(def_id) {
+ FnLikeNode::from_node(self.tcx.map.get(fn_id)).map_or(false, |fn_like| {
+ fn_like.constness() == hir::Constness::Const
+ })
+ } else {
+ self.tcx.sess.cstore.is_const_fn(def_id)
+ };
}
}
impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
- NestedVisitorMap::OnlyBodies(&self.tcx.map)
+ NestedVisitorMap::None
}
- fn visit_item(&mut self, i: &'tcx hir::Item) {
- debug!("visit_item(item={})", self.tcx.map.node_to_string(i.id));
- assert_eq!(self.mode, Mode::Var);
- match i.node {
- hir::ItemStatic(_, hir::MutImmutable, ref expr) => {
- self.global_expr(Mode::Static, &expr);
- }
- hir::ItemStatic(_, hir::MutMutable, ref expr) => {
- self.global_expr(Mode::StaticMut, &expr);
- }
- hir::ItemConst(_, ref expr) => {
- self.global_expr(Mode::Const, &expr);
- }
- hir::ItemEnum(ref enum_definition, _) => {
- for var in &enum_definition.variants {
- if let Some(ref ex) = var.node.disr_expr {
- self.global_expr(Mode::Const, &ex);
- }
- }
- }
- _ => {
- intravisit::walk_item(self, i);
+ fn visit_nested_body(&mut self, body: hir::BodyId) {
+ match self.tcx.rvalue_promotable_to_static.borrow_mut().entry(body.node_id) {
+ Entry::Occupied(_) => return,
+ Entry::Vacant(entry) => {
+ // Prevent infinite recursion on re-entry.
+ entry.insert(false);
}
}
- }
- fn visit_trait_item(&mut self, t: &'tcx hir::TraitItem) {
- match t.node {
- hir::ConstTraitItem(_, ref default) => {
- if let Some(ref expr) = *default {
- self.global_expr(Mode::Const, &expr);
- } else {
- intravisit::walk_trait_item(self, t);
- }
- }
- _ => self.with_mode(Mode::Var, |v| intravisit::walk_trait_item(v, t)),
- }
- }
+ let item_id = self.tcx.map.body_owner(body);
- fn visit_impl_item(&mut self, i: &'tcx hir::ImplItem) {
- match i.node {
- hir::ImplItemKind::Const(_, ref expr) => {
- self.global_expr(Mode::Const, &expr);
- }
- _ => self.with_mode(Mode::Var, |v| intravisit::walk_impl_item(v, i)),
+ let outer_in_fn = self.in_fn;
+ self.in_fn = match MirSource::from_node(self.tcx, item_id) {
+ MirSource::Fn(_) => true,
+ _ => false
+ };
+
+ let body = self.tcx.map.body(body);
+ if !self.in_fn {
+ self.check_const_eval(&body.value);
}
- }
- fn visit_fn(&mut self,
- fk: FnKind<'tcx>,
- fd: &'tcx hir::FnDecl,
- b: hir::ExprId,
- s: Span,
- fn_id: ast::NodeId) {
- self.fn_like(fk, fd, b, s, fn_id);
+ let param_env = ty::ParameterEnvironment::for_item(self.tcx, item_id);
+ let outer_param_env = mem::replace(&mut self.param_env, param_env);
+ self.tcx.infer_ctxt(None, Some(self.param_env.clone()), Reveal::NotSpecializable)
+ .enter(|infcx| euv::ExprUseVisitor::new(self, &infcx).consume_body(body));
+
+ self.visit_body(body);
+
+ self.param_env = outer_param_env;
+ self.in_fn = outer_in_fn;
}
fn visit_pat(&mut self, p: &'tcx hir::Pat) {
match p.node {
PatKind::Lit(ref lit) => {
- self.global_expr(Mode::Const, &lit);
+ self.check_const_eval(lit);
}
PatKind::Range(ref start, ref end) => {
- self.global_expr(Mode::Const, &start);
- self.global_expr(Mode::Const, &end);
+ self.check_const_eval(start);
+ self.check_const_eval(end);
match compare_lit_exprs(self.tcx, p.span, start, end) {
Ok(Ordering::Less) |
Err(ErrorReported) => {}
}
}
- _ => intravisit::walk_pat(self, p),
+ _ => {}
}
+ intravisit::walk_pat(self, p);
}
- fn visit_block(&mut self, block: &'tcx hir::Block) {
- // Check all statements in the block
- for stmt in &block.stmts {
- match stmt.node {
- hir::StmtDecl(ref decl, _) => {
- match decl.node {
- hir::DeclLocal(_) => {}
- // Item statements are allowed
- hir::DeclItem(_) => continue,
+ fn visit_stmt(&mut self, stmt: &'tcx hir::Stmt) {
+ match stmt.node {
+ hir::StmtDecl(ref decl, _) => {
+ match decl.node {
+ hir::DeclLocal(_) => {
+ self.promotable = false;
}
+ // Item statements are allowed
+ hir::DeclItem(_) => {}
}
- hir::StmtExpr(..) => {}
- hir::StmtSemi(..) => {}
}
- self.add_qualif(ConstQualif::NOT_CONST);
+ hir::StmtExpr(..) |
+ hir::StmtSemi(..) => {
+ self.promotable = false;
+ }
}
- intravisit::walk_block(self, block);
+ intravisit::walk_stmt(self, stmt);
}
fn visit_expr(&mut self, ex: &'tcx hir::Expr) {
- let mut outer = self.qualif;
- self.qualif = ConstQualif::empty();
+ let outer = self.promotable;
+ self.promotable = true;
let node_ty = self.tcx.tables().node_id_to_type(ex.id);
check_expr(self, ex, node_ty);
check_adjustments(self, ex);
- // Special-case some expressions to avoid certain flags bubbling up.
- match ex.node {
- hir::ExprCall(ref callee, ref args) => {
- for arg in args {
- self.visit_expr(&arg)
+ if let hir::ExprMatch(ref discr, ref arms, _) = ex.node {
+ // Compute the most demanding borrow from all the arms'
+ // patterns and set that on the discriminator.
+ let mut mut_borrow = false;
+ for pat in arms.iter().flat_map(|arm| &arm.pats) {
+ if self.mut_rvalue_borrows.remove(&pat.id) {
+ mut_borrow = true;
}
-
- let inner = self.qualif;
- self.visit_expr(&callee);
- // The callee's size doesn't count in the call.
- let added = self.qualif - inner;
- self.qualif = inner | (added - ConstQualif::NON_ZERO_SIZED);
}
- hir::ExprRepeat(ref element, _) => {
- self.visit_expr(&element);
- // The count is checked elsewhere (typeck).
- let count = match node_ty.sty {
- ty::TyArray(_, n) => n,
- _ => bug!(),
- };
- // [element; 0] is always zero-sized.
- if count == 0 {
- self.qualif.remove(ConstQualif::NON_ZERO_SIZED | ConstQualif::PREFER_IN_PLACE);
- }
+ if mut_borrow {
+ self.mut_rvalue_borrows.insert(discr.id);
}
- hir::ExprMatch(ref discr, ref arms, _) => {
- // Compute the most demanding borrow from all the arms'
- // patterns and set that on the discriminator.
- let mut borrow = None;
- for pat in arms.iter().flat_map(|arm| &arm.pats) {
- let pat_borrow = self.rvalue_borrows.remove(&pat.id);
- match (borrow, pat_borrow) {
- (None, _) |
- (_, Some(hir::MutMutable)) => {
- borrow = pat_borrow;
- }
- _ => {}
- }
- }
- if let Some(mutbl) = borrow {
- self.record_borrow(discr.id, mutbl);
- }
- intravisit::walk_expr(self, ex);
- }
- _ => intravisit::walk_expr(self, ex),
}
+ intravisit::walk_expr(self, ex);
+
// Handle borrows on (or inside the autorefs of) this expression.
- match self.rvalue_borrows.remove(&ex.id) {
- Some(hir::MutImmutable) => {
- // Constants cannot be borrowed if they contain interior mutability as
- // it means that our "silent insertion of statics" could change
- // initializer values (very bad).
- // If the type doesn't have interior mutability, then `ConstQualif::MUTABLE_MEM` has
- // propagated from another error, so erroring again would be just noise.
- let tc = node_ty.type_contents(self.tcx);
- if self.qualif.intersects(ConstQualif::MUTABLE_MEM) && tc.interior_unsafe() {
- outer = outer | ConstQualif::NOT_CONST;
- }
- // If the reference has to be 'static, avoid in-place initialization
- // as that will end up pointing to the stack instead.
- if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
- self.qualif = self.qualif - ConstQualif::PREFER_IN_PLACE;
- self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
- }
- }
- Some(hir::MutMutable) => {
- // `&mut expr` means expr could be mutated, unless it's zero-sized.
- if self.qualif.intersects(ConstQualif::NON_ZERO_SIZED) {
- if self.mode == Mode::Var {
- outer = outer | ConstQualif::NOT_CONST;
- self.add_qualif(ConstQualif::MUTABLE_MEM);
- }
- }
- if !self.qualif.intersects(ConstQualif::NON_STATIC_BORROWS) {
- self.add_qualif(ConstQualif::HAS_STATIC_BORROWS);
- }
- }
- None => {}
+ if self.mut_rvalue_borrows.remove(&ex.id) {
+ self.promotable = false;
}
- if self.mode == Mode::Var && !self.qualif.intersects(ConstQualif::NOT_CONST) {
+ if self.in_fn && self.promotable {
match eval_const_expr_partial(self.tcx, ex, ExprTypeChecked, None) {
Ok(_) => {}
Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) |
}
}
- self.tcx.const_qualif_map.borrow_mut().insert(ex.id, self.qualif);
- // Don't propagate certain flags.
- self.qualif = outer | (self.qualif - ConstQualif::HAS_STATIC_BORROWS);
+ self.tcx.rvalue_promotable_to_static.borrow_mut().insert(ex.id, self.promotable);
+ self.promotable &= outer;
}
}
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() => {
- v.add_qualif(ConstQualif::NEEDS_DROP);
+ v.promotable = false;
}
_ => {}
}
hir::ExprUnary(..) |
hir::ExprBinary(..) |
hir::ExprIndex(..) if v.tcx.tables().method_map.contains_key(&method_call) => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
hir::ExprBox(_) => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
hir::ExprUnary(op, ref inner) => {
match v.tcx.tables().node_id_to_type(inner.id).sty {
ty::TyRawPtr(_) => {
assert!(op == hir::UnDeref);
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
_ => {}
}
op.node == hir::BiLe || op.node == hir::BiLt ||
op.node == hir::BiGe || op.node == hir::BiGt);
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
_ => {}
}
match v.tcx.cast_kinds.borrow().get(&from.id) {
None => span_bug!(e.span, "no kind for cast"),
Some(&CastKind::PtrAddrCast) | Some(&CastKind::FnPtrAddrCast) => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
_ => {}
}
hir::ExprPath(ref qpath) => {
let def = v.tcx.tables().qpath_def(qpath, e.id);
match def {
- Def::VariantCtor(_, CtorKind::Const) => {
- // Size is determined by the whole enum, may be non-zero.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
Def::VariantCtor(..) | Def::StructCtor(..) |
Def::Fn(..) | Def::Method(..) => {}
- Def::Static(..) => {
- match v.mode {
- Mode::Static | Mode::StaticMut => {}
- Mode::Const | Mode::ConstFn => {}
- Mode::Var => v.add_qualif(ConstQualif::NOT_CONST)
- }
- }
- Def::Const(did) | Def::AssociatedConst(did) => {
- let substs = Some(v.tcx.tables().node_id_item_substs(e.id)
- .unwrap_or_else(|| v.tcx.intern_substs(&[])));
- if let Some((expr, _)) = lookup_const_by_id(v.tcx, did, substs) {
- let inner = v.global_expr(Mode::Const, expr);
- v.add_qualif(inner);
- }
- }
- Def::Local(..) if v.mode == Mode::ConstFn => {
- // Sadly, we can't determine whether the types are zero-sized.
- v.add_qualif(ConstQualif::NOT_CONST | ConstQualif::NON_ZERO_SIZED);
+ Def::AssociatedConst(_) => v.add_type(node_ty),
+ Def::Const(did) => {
+ v.promotable &= if let Some(node_id) = v.tcx.map.as_local_node_id(did) {
+ match v.tcx.map.expect_item(node_id).node {
+ hir::ItemConst(_, body) => {
+ v.visit_nested_body(body);
+ v.tcx.rvalue_promotable_to_static.borrow()[&body.node_id]
+ }
+ _ => false
+ }
+ } else {
+ v.tcx.sess.cstore.const_is_rvalue_promotable_to_static(did)
+ };
}
_ => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
}
}
} else {
Def::Err
};
- let is_const = match def {
+ match def {
Def::StructCtor(_, CtorKind::Fn) |
- Def::VariantCtor(_, CtorKind::Fn) => {
- // `NON_ZERO_SIZED` is about the call result, not about the ctor itself.
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- true
- }
+ Def::VariantCtor(_, CtorKind::Fn) => {}
Def::Fn(did) => {
- v.handle_const_fn_call(e, did, node_ty)
+ v.handle_const_fn_call(did, node_ty)
}
Def::Method(did) => {
match v.tcx.associated_item(did).container {
ty::ImplContainer(_) => {
- v.handle_const_fn_call(e, did, node_ty)
+ v.handle_const_fn_call(did, node_ty)
}
- ty::TraitContainer(_) => false
+ ty::TraitContainer(_) => v.promotable = false
}
}
- _ => false
- };
- if !is_const {
- v.add_qualif(ConstQualif::NOT_CONST);
+ _ => v.promotable = false
}
}
hir::ExprMethodCall(..) => {
let method = v.tcx.tables().method_map[&method_call];
- let is_const = match v.tcx.associated_item(method.def_id).container {
- ty::ImplContainer(_) => v.handle_const_fn_call(e, method.def_id, node_ty),
- ty::TraitContainer(_) => false
- };
- if !is_const {
- v.add_qualif(ConstQualif::NOT_CONST);
+ match v.tcx.associated_item(method.def_id).container {
+ ty::ImplContainer(_) => v.handle_const_fn_call(method.def_id, node_ty),
+ ty::TraitContainer(_) => v.promotable = false
}
}
hir::ExprStruct(..) => {
if let ty::TyAdt(adt, ..) = v.tcx.tables().expr_ty(e).sty {
// unsafe_cell_type doesn't necessarily exist with no_core
if Some(adt.did) == v.tcx.lang_items.unsafe_cell_type() {
- v.add_qualif(ConstQualif::MUTABLE_MEM);
+ v.promotable = false;
}
}
}
hir::ExprLit(_) |
- hir::ExprAddrOf(..) => {
- v.add_qualif(ConstQualif::NON_ZERO_SIZED);
- }
-
- hir::ExprRepeat(..) => {
- v.add_qualif(ConstQualif::PREFER_IN_PLACE);
- }
+ hir::ExprAddrOf(..) |
+ hir::ExprRepeat(..) => {}
hir::ExprClosure(..) => {
// Paths in constant contexts cannot refer to local variables,
// as there are none, and thus closures can't have upvars there.
if v.tcx.with_freevars(e.id, |fv| !fv.is_empty()) {
- assert!(v.mode == Mode::Var,
- "global closures can't capture anything");
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
}
hir::ExprAssign(..) |
hir::ExprAssignOp(..) |
hir::ExprInlineAsm(..) => {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
}
}
Some(Adjust::DerefRef { autoderefs, .. }) => {
if (0..autoderefs as u32)
.any(|autoderef| v.tcx.tables().is_overloaded_autoderef(e.id, autoderef)) {
- v.add_qualif(ConstQualif::NOT_CONST);
+ v.promotable = false;
}
}
}
tcx.visit_all_item_likes_in_krate(DepNode::CheckConst,
&mut CheckCrateVisitor {
tcx: tcx,
- mode: Mode::Var,
- qualif: ConstQualif::NOT_CONST,
- rvalue_borrows: NodeMap(),
+ in_fn: false,
+ promotable: false,
+ mut_rvalue_borrows: NodeSet(),
+ param_env: tcx.empty_parameter_environment(),
}.as_deep_visitor());
tcx.sess.abort_if_errors();
}
fn consume(&mut self,
_consume_id: ast::NodeId,
_consume_span: Span,
- cmt: mc::cmt,
- _mode: euv::ConsumeMode) {
- let mut cur = &cmt;
- loop {
- match cur.cat {
- Categorization::StaticItem => {
- break;
- }
- Categorization::Deref(ref cmt, ..) |
- Categorization::Downcast(ref cmt, _) |
- Categorization::Interior(ref cmt, _) => cur = cmt,
+ _cmt: mc::cmt,
+ _mode: euv::ConsumeMode) {}
- Categorization::Rvalue(..) |
- Categorization::Upvar(..) |
- Categorization::Local(..) => break,
- }
- }
- }
fn borrow(&mut self,
borrow_id: ast::NodeId,
_borrow_span: Span,
// Ignore the dummy immutable borrow created by EUV.
break;
}
- let mutbl = bk.to_mutbl_lossy();
- if mutbl == hir::MutMutable && self.mode == Mode::StaticMut {
- // Mutable slices are the only `&mut` allowed in
- // globals, but only in `static mut`, nowhere else.
- // FIXME: This exception is really weird... there isn't
- // any fundamental reason to restrict this based on
- // type of the expression. `&mut [1]` has exactly the
- // same representation as &mut 1.
- match cmt.ty.sty {
- ty::TyArray(..) |
- ty::TySlice(_) => break,
- _ => {}
- }
+ if bk.to_mutbl_lossy() == hir::MutMutable {
+ self.mut_rvalue_borrows.insert(borrow_id);
}
- self.record_borrow(borrow_id, mutbl);
break;
}
Categorization::StaticItem => {
self.visit_item(nested_item)
}
+ fn visit_nested_trait_item(&mut self, trait_item_id: hir::TraitItemId) {
+ let nested_trait_item = self.krate.unwrap().trait_item(trait_item_id);
+ self.visit_trait_item(nested_trait_item)
+ }
+
fn visit_nested_impl_item(&mut self, impl_item_id: hir::ImplItemId) {
let nested_impl_item = self.krate.unwrap().impl_item(impl_item_id);
self.visit_impl_item(nested_impl_item)
fn visit_fn(&mut self,
fk: hir_visit::FnKind<'v>,
fd: &'v hir::FnDecl,
- b: hir::ExprId,
+ b: hir::BodyId,
s: Span,
id: NodeId) {
self.record("FnDecl", Id::None, fd);
self.with_context(Loop(LoopKind::Loop(source)), |v| v.visit_block(&b));
}
hir::ExprClosure(.., b, _) => {
- self.with_context(Closure, |v| v.visit_body(b));
+ self.with_context(Closure, |v| v.visit_nested_body(b));
}
hir::ExprBreak(label, ref opt_expr) => {
if opt_expr.is_some() {
fn visit_fn(&mut self,
fk: intravisit::FnKind<'tcx>,
fd: &'tcx hir::FnDecl,
- b: hir::ExprId,
+ b: hir::BodyId,
s: Span,
fn_id: ast::NodeId) {
// FIXME (@jroesch) change this to be an inference context
tcx: infcx.tcx,
param_env: ¶m_env
};
- let body = infcx.tcx.map.expr(b);
+ let body = infcx.tcx.map.body(b);
let mut euv = euv::ExprUseVisitor::new(&mut delegate, &infcx);
- euv.walk_fn(fd, body);
+ euv.consume_body(body);
});
intravisit::walk_fn(self, fk, fd, b, s, fn_id)
}
// variant definitions with the discriminant expression that applies to
// each one. If the variant uses the default values (starting from `0`),
// then `None` is stored.
- discriminant_map: NodeMap<Option<&'ast hir::Expr>>,
+ discriminant_map: NodeMap<Option<hir::BodyId>>,
detected_recursive_ids: NodeSet,
}
fn visit_trait_item(&mut self, ti: &'ast hir::TraitItem) {
match ti.node {
- hir::ConstTraitItem(_, ref default) => {
+ hir::TraitItemKind::Const(_, ref default) => {
if let Some(_) = *default {
let mut recursion_visitor = CheckItemRecursionVisitor::new(self, &ti.span);
recursion_visitor.visit_trait_item(ti);
root_span: &'b Span,
sess: &'b Session,
ast_map: &'b ast_map::Map<'ast>,
- discriminant_map: &'a mut NodeMap<Option<&'ast hir::Expr>>,
+ discriminant_map: &'a mut NodeMap<Option<hir::BodyId>>,
idstack: Vec<ast::NodeId>,
detected_recursive_ids: &'a mut NodeSet,
}
variant_stack.push(variant.node.data.id());
// When we find an expression, every variant currently on the stack
// is affected by that expression.
- if let Some(ref expr) = variant.node.disr_expr {
+ if let Some(expr) = variant.node.disr_expr {
for id in &variant_stack {
self.discriminant_map.insert(*id, Some(expr));
}
_: &'ast hir::Generics,
_: ast::NodeId) {
let variant_id = variant.node.data.id();
- let maybe_expr;
- if let Some(get_expr) = self.discriminant_map.get(&variant_id) {
- // This is necessary because we need to let the `discriminant_map`
- // borrow fall out of scope, so that we can reborrow farther down.
- maybe_expr = (*get_expr).clone();
- } else {
+ let maybe_expr = *self.discriminant_map.get(&variant_id).unwrap_or_else(|| {
span_bug!(variant.span,
"`check_static_recursion` attempted to visit \
variant with unknown discriminant")
- }
+ });
// If `maybe_expr` is `None`, that's because no discriminant is
// specified that affects this variant. Thus, no risk of recursion.
if let Some(expr) = maybe_expr {
+ let expr = &self.ast_map.body(expr).value;
self.with_item_id_pushed(expr.id, |v| intravisit::walk_expr(v, expr), expr.span);
}
}
mod x86;
mod arm;
mod aarch64;
+mod nvptx;
impl Intrinsic {
pub fn find(name: &str) -> Option<Intrinsic> {
arm::find(name)
} else if name.starts_with("aarch64_") {
aarch64::find(name)
+ } else if name.starts_with("nvptx_") {
+ nvptx::find(name)
} else {
None
}
--- /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.
+
+// DO NOT EDIT: autogenerated by etc/platform-intrinsics/generator.py
+// ignore-tidy-linelength
+
+#![allow(unused_imports)]
+
+use {Intrinsic, Type};
+use IntrinsicDef::Named;
+
+// The default inlining settings trigger a pathological behaviour in
+// LLVM, which causes makes compilation very slow. See #28273.
+#[inline(never)]
+pub fn find(name: &str) -> Option<Intrinsic> {
+ if !name.starts_with("nvptx") { return None }
+ Some(match &name["nvptx".len()..] {
+ "_syncthreads" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::VOID,
+ definition: Named("llvm.cuda.syncthreads")
+ },
+ "_block_dim_x" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.ntid.x")
+ },
+ "_block_dim_y" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.ntid.y")
+ },
+ "_block_dim_z" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.ntid.z")
+ },
+ "_block_idx_x" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.ctaid.x")
+ },
+ "_block_idx_y" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.ctaid.y")
+ },
+ "_block_idx_z" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.ctaid.z")
+ },
+ "_grid_dim_x" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.nctaid.x")
+ },
+ "_grid_dim_y" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.nctaid.y")
+ },
+ "_grid_dim_z" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.nctaid.z")
+ },
+ "_thread_idx_x" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.tid.x")
+ },
+ "_thread_idx_y" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.tid.y")
+ },
+ "_thread_idx_z" => Intrinsic {
+ inputs: { static INPUTS: [&'static Type; 0] = []; &INPUTS },
+ output: &::I32,
+ definition: Named("llvm.nvvm.read.ptx.sreg.tid.z")
+ },
+ _ => return None,
+ })
+}
authors = ["The Rust Project Developers"]
name = "rustc_plugin"
version = "0.0.0"
+build = false
[lib]
name = "rustc_plugin"
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
#[doc(hidden)]
pub attributes: Vec<(String, AttributeType)>,
+
+ whitelisted_custom_derives: Vec<ast::Name>,
}
impl<'a> Registry<'a> {
llvm_passes: vec![],
attributes: vec![],
mir_passes: Vec::new(),
+ whitelisted_custom_derives: Vec::new(),
}
}
}));
}
+ /// This can be used in place of `register_syntax_extension` to register legacy custom derives
+ /// (i.e. attribute syntax extensions whose name begins with `derive_`). Legacy custom
+ /// derives defined by this function do not trigger deprecation warnings when used.
+ #[unstable(feature = "rustc_private", issue = "27812")]
+ #[rustc_deprecated(since = "1.15.0", reason = "replaced by macros 1.1 (RFC 1861)")]
+ pub fn register_custom_derive(&mut self, name: ast::Name, extension: SyntaxExtension) {
+ assert!(name.as_str().starts_with("derive_"));
+ self.whitelisted_custom_derives.push(name);
+ self.register_syntax_extension(name, extension);
+ }
+
+ pub fn take_whitelisted_custom_derives(&mut self) -> Vec<ast::Name> {
+ ::std::mem::replace(&mut self.whitelisted_custom_derives, Vec::new())
+ }
+
/// Register a macro of the usual kind.
///
/// This is a convenience wrapper for `register_syntax_extension`.
use rustc::dep_graph::DepNode;
use rustc::hir::{self, PatKind};
use rustc::hir::def::{self, Def, CtorKind};
-use rustc::hir::def_id::DefId;
+use rustc::hir::def_id::{CRATE_DEF_INDEX, DefId};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::itemlikevisit::DeepVisitor;
use rustc::hir::pat_util::EnumerateAndAdjustIterator;
}
hir::ItemImpl(.., None, _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
- let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
- if impl_item.vis == hir::Public {
- self.update(impl_item.id, item_level);
+ if impl_item_ref.vis == hir::Public {
+ self.update(impl_item_ref.id.node_id, item_level);
}
}
}
hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => {
for impl_item_ref in impl_item_refs {
- let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
- self.update(impl_item.id, item_level);
+ self.update(impl_item_ref.id.node_id, item_level);
}
}
- hir::ItemTrait(.., ref trait_items) => {
- for trait_item in trait_items {
- self.update(trait_item.id, item_level);
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ for trait_item_ref in trait_item_refs {
+ self.update(trait_item_ref.id.node_id, item_level);
}
}
hir::ItemStruct(ref def, _) | hir::ItemUnion(ref def, _) => {
self.reach(item.id).generics().predicates().item_type();
}
}
- hir::ItemTrait(.., ref trait_items) => {
+ hir::ItemTrait(.., ref trait_item_refs) => {
if item_level.is_some() {
self.reach(item.id).generics().predicates();
- for trait_item in trait_items {
- let mut reach = self.reach(trait_item.id);
+ for trait_item_ref in trait_item_refs {
+ let mut reach = self.reach(trait_item_ref.id.node_id);
reach.generics().predicates();
- if let hir::TypeTraitItem(_, None) = trait_item.node {
+ if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
+ !trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
reach.item_type();
}
}
// Visit everything except for private impl items
- hir::ItemImpl(.., ref trait_ref, _, ref impl_items) => {
+ hir::ItemImpl(.., ref trait_ref, _, ref impl_item_refs) => {
if item_level.is_some() {
self.reach(item.id).generics().predicates().impl_trait_ref();
- for impl_item in impl_items {
- let id = impl_item.id.node_id;
+ for impl_item_ref in impl_item_refs {
+ let id = impl_item_ref.id.node_id;
if trait_ref.is_some() || self.get(id).is_some() {
self.reach(id).generics().predicates().item_type();
}
struct PrivacyVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
- curitem: ast::NodeId,
+ curitem: DefId,
in_foreign: bool,
}
Some(node_id) =>
ty::Visibility::from_hir(&self.tcx.map.expect_item(node_id).vis, node_id, self.tcx),
None => self.tcx.sess.cstore.visibility(did),
- }.is_accessible_from(self.curitem, &self.tcx.map)
+ }.is_accessible_from(self.curitem, self.tcx)
}
// Checks that a field is in scope.
fn check_field(&mut self, span: Span, def: &'tcx ty::AdtDef, field: &'tcx ty::FieldDef) {
- if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, &self.tcx.map) {
+ if !def.is_enum() && !field.vis.is_accessible_from(self.curitem, self.tcx) {
struct_span_err!(self.tcx.sess, span, E0451, "field `{}` of {} `{}` is private",
field.name, def.variant_descr(), self.tcx.item_path_str(def.did))
.span_label(span, &format!("field `{}` is private", field.name))
}
fn visit_item(&mut self, item: &'tcx hir::Item) {
- let orig_curitem = replace(&mut self.curitem, item.id);
+ let orig_curitem = replace(&mut self.curitem, self.tcx.map.local_def_id(item.id));
intravisit::walk_item(self, item);
self.curitem = orig_curitem;
}
if let Def::StructCtor(_, CtorKind::Fn) = path.def {
let adt_def = self.tcx.expect_variant_def(path.def);
let private_indexes = adt_def.fields.iter().enumerate().filter(|&(_, field)| {
- !field.vis.is_accessible_from(self.curitem, &self.tcx.map)
+ !field.vis.is_accessible_from(self.curitem, self.tcx)
}).map(|(i, _)| i).collect::<Vec<_>>();
if !private_indexes.is_empty() {
// methods will be visible as `Public::foo`.
let mut found_pub_static = false;
for impl_item_ref in impl_item_refs {
- let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
- match impl_item.node {
- hir::ImplItemKind::Const(..) => {
- if self.item_is_public(&impl_item.id, &impl_item.vis) {
+ if self.item_is_public(&impl_item_ref.id.node_id, &impl_item_ref.vis) {
+ let impl_item = self.tcx.map.impl_item(impl_item_ref.id);
+ match impl_item_ref.kind {
+ hir::AssociatedItemKind::Const => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
- }
- hir::ImplItemKind::Method(ref sig, _) => {
- if !sig.decl.has_self() &&
- self.item_is_public(&impl_item.id, &impl_item.vis) {
+ hir::AssociatedItemKind::Method { has_self: false } => {
found_pub_static = true;
intravisit::walk_impl_item(self, impl_item);
}
+ _ => {}
}
- _ => {}
}
}
if found_pub_static {
ty::TyAdt(adt, _) => Some(adt.did),
ty::TyDynamic(ref obj, ..) => obj.principal().map(|p| p.def_id()),
ty::TyProjection(ref proj) => {
- if self.required_visibility == ty::Visibility::PrivateExternal {
+ if self.required_visibility == ty::Visibility::Invisible {
// Conservatively approximate the whole type alias as public without
// recursing into its components when determining impl publicity.
// For example, `impl <Type as Trait>::Alias {...}` may be a public impl
let item = self.tcx.map.expect_item(node_id);
let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
- if !vis.is_at_least(self.min_visibility, &self.tcx.map) {
+ if !vis.is_at_least(self.min_visibility, self.tcx) {
self.min_visibility = vis;
}
- if !vis.is_at_least(self.required_visibility, &self.tcx.map) {
+ if !vis.is_at_least(self.required_visibility, self.tcx) {
if self.tcx.sess.features.borrow().pub_restricted || self.has_old_errors {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0446,
"private type `{}` in public interface", ty);
let item = self.tcx.map.expect_item(node_id);
let vis = ty::Visibility::from_hir(&item.vis, node_id, self.tcx);
- if !vis.is_at_least(self.min_visibility, &self.tcx.map) {
+ if !vis.is_at_least(self.min_visibility, self.tcx) {
self.min_visibility = vis;
}
- if !vis.is_at_least(self.required_visibility, &self.tcx.map) {
+ if !vis.is_at_least(self.required_visibility, self.tcx) {
if self.tcx.sess.features.borrow().pub_restricted || self.has_old_errors {
struct_span_err!(self.tcx.sess, self.span, E0445,
"private trait `{}` in public interface", trait_ref)
fn visit_item(&mut self, item: &'tcx hir::Item) {
let tcx = self.tcx;
let min = |vis1: ty::Visibility, vis2| {
- if vis1.is_at_least(vis2, &tcx.map) { vis2 } else { vis1 }
+ if vis1.is_at_least(vis2, tcx) { vis2 } else { vis1 }
};
let item_visibility = ty::Visibility::from_hir(&item.vis, item.id, tcx);
self.inner_visibility = item_visibility;
intravisit::walk_item(self, item);
}
- hir::ItemTrait(.., ref trait_items) => {
+ hir::ItemTrait(.., ref trait_item_refs) => {
self.check(item.id, item_visibility).generics().predicates();
- for trait_item in trait_items {
- let mut check = self.check(trait_item.id, item_visibility);
+ for trait_item_ref in trait_item_refs {
+ let mut check = self.check(trait_item_ref.id.node_id, item_visibility);
check.generics().predicates();
- if let hir::TypeTraitItem(_, None) = trait_item.node {
+ if trait_item_ref.kind == hir::AssociatedItemKind::Type &&
+ !trait_item_ref.defaultness.has_value() {
// No type to visit.
} else {
check.item_type();
// An inherent impl is public when its type is public
// Subitems of inherent impls have their own publicity
hir::ItemImpl(.., None, _, ref impl_item_refs) => {
- let ty_vis = self.check(item.id, ty::Visibility::PrivateExternal)
- .item_type().min_visibility;
+ let ty_vis =
+ self.check(item.id, ty::Visibility::Invisible).item_type().min_visibility;
self.check(item.id, ty_vis).generics().predicates();
for impl_item_ref in impl_item_refs {
// A trait impl is public when both its type and its trait are public
// Subitems of trait impls have inherited publicity
hir::ItemImpl(.., Some(_), _, ref impl_item_refs) => {
- let vis = self.check(item.id, ty::Visibility::PrivateExternal)
+ let vis = self.check(item.id, ty::Visibility::Invisible)
.item_type().impl_trait_ref().min_visibility;
self.check(item.id, vis).generics().predicates();
for impl_item_ref in impl_item_refs {
// Use the parent map to check the privacy of everything
let mut visitor = PrivacyVisitor {
- curitem: ast::DUMMY_NODE_ID,
+ curitem: DefId::local(CRATE_DEF_INDEX),
in_foreign: false,
tcx: tcx,
};
use syntax::ext::expand::mark_tts;
use syntax::ext::hygiene::Mark;
use syntax::ext::tt::macro_rules;
+use syntax::parse::token;
use syntax::symbol::keywords;
use syntax::visit::{self, Visitor};
// Extract and intern the module part of the path. For
// globs and lists, the path is found directly in the AST;
// for simple paths we have to munge the path a little.
- let module_path: Vec<_> = match view_path.node {
+ let mut module_path: Vec<_> = match view_path.node {
ViewPathSimple(_, ref full_path) => {
full_path.segments
.split_last()
}
};
+ // This can be removed once warning cycle #36888 is complete.
+ if module_path.len() >= 2 && module_path[0].name == keywords::CrateRoot.name() &&
+ token::Ident(module_path[1]).is_path_segment_keyword() {
+ module_path.remove(0);
+ }
+
// Build up the import directives.
let is_prelude = attr::contains_name(&item.attrs, "prelude_import");
let rename = node.rename.unwrap_or(node.name);
(module_path.clone(), node.name, rename)
} else {
- let ident = match module_path.last() {
- Some(&ident) => ident,
- None => {
- resolve_error(
- self,
- source_item.span,
- ResolutionError::
- SelfImportOnlyInImportListWithNonEmptyPrefix
- );
- continue;
- }
- };
+ let ident = *module_path.last().unwrap();
+ if ident.name == keywords::CrateRoot.name() {
+ resolve_error(
+ self,
+ source_item.span,
+ ResolutionError::
+ SelfImportOnlyInImportListWithNonEmptyPrefix
+ );
+ continue;
+ }
let module_path = module_path.split_last().unwrap().1;
let rename = node.rename.unwrap_or(ident);
(module_path.to_vec(), ident, rename)
ViewPathGlob(_) => {
let subclass = GlobImport {
is_prelude: is_prelude,
- max_vis: Cell::new(ty::Visibility::PrivateExternal),
+ max_vis: Cell::new(ty::Visibility::Invisible),
};
self.add_import_directive(
module_path, subclass, view_path.span, item.id, vis, expansion,
ItemKind::Mod(..) if item.ident == keywords::Invalid.ident() => {} // Crate root
ItemKind::Mod(..) => {
- let def = Def::Mod(self.definitions.local_def_id(item.id));
+ let def_id = self.definitions.local_def_id(item.id);
+ let module_kind = ModuleKind::Def(Def::Mod(def_id), ident.name);
let module = self.arenas.alloc_module(ModuleData {
no_implicit_prelude: parent.no_implicit_prelude || {
attr::contains_name(&item.attrs, "no_implicit_prelude")
},
- normal_ancestor_id: Some(item.id),
- ..ModuleData::new(Some(parent), ModuleKind::Def(def, ident.name))
+ ..ModuleData::new(Some(parent), module_kind, def_id)
});
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
- self.module_map.insert(item.id, module);
+ self.module_map.insert(def_id, module);
// Descend into the module.
self.current_module = module;
ItemKind::Enum(ref enum_definition, _) => {
let def = Def::Enum(self.definitions.local_def_id(item.id));
- let module = self.new_module(parent, ModuleKind::Def(def, ident.name), true);
+ let module_kind = ModuleKind::Def(def, ident.name);
+ let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
for variant in &(*enum_definition).variants {
let def_id = self.definitions.local_def_id(item.id);
// Add all the items within to a new module.
- let module =
- self.new_module(parent, ModuleKind::Def(Def::Trait(def_id), ident.name), true);
+ let module_kind = ModuleKind::Def(Def::Trait(def_id), ident.name);
+ let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
self.define(parent, ident, TypeNS, (module, vis, sp, expansion));
self.current_module = module;
}
fn build_reduced_graph_for_block(&mut self, block: &Block) {
let parent = self.current_module;
if self.block_needs_anonymous_module(block) {
- let block_id = block.id;
-
- debug!("(building reduced graph for block) creating a new anonymous module for block \
- {}",
- block_id);
-
- let new_module = self.new_module(parent, ModuleKind::Block(block_id), true);
- self.module_map.insert(block_id, new_module);
- self.current_module = new_module; // Descend into the block.
+ let module =
+ self.new_module(parent, ModuleKind::Block(block.id), parent.normal_ancestor_id);
+ self.block_map.insert(block.id, module);
+ self.current_module = module; // Descend into the block.
}
}
let ident = Ident::with_empty_ctxt(child.name);
let def = child.def;
let def_id = def.def_id();
- let vis = match def {
- Def::Macro(..) => ty::Visibility::Public,
- _ if parent.is_trait() => ty::Visibility::Public,
- _ => self.session.cstore.visibility(def_id),
- };
+ let vis = self.session.cstore.visibility(def_id);
match def {
Def::Mod(..) | Def::Enum(..) => {
- let module = self.new_module(parent, ModuleKind::Def(def, ident.name), false);
+ let module = self.new_module(parent, ModuleKind::Def(def, ident.name), def_id);
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
}
- Def::Variant(..) => {
+ Def::Variant(..) | Def::TyAlias(..) => {
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
}
- Def::VariantCtor(..) => {
- self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
- }
- Def::Fn(..) |
- Def::Static(..) |
- Def::Const(..) |
- Def::AssociatedConst(..) |
- Def::Method(..) => {
+ Def::Fn(..) | Def::Static(..) | Def::Const(..) |
+ Def::VariantCtor(..) | Def::StructCtor(..) => {
self.define(parent, ident, ValueNS, (def, vis, DUMMY_SP, Mark::root()));
}
Def::Trait(..) => {
- let module = self.new_module(parent, ModuleKind::Def(def, ident.name), false);
+ let module_kind = ModuleKind::Def(def, ident.name);
+ let module = self.new_module(parent, module_kind, parent.normal_ancestor_id);
self.define(parent, ident, TypeNS, (module, vis, DUMMY_SP, Mark::root()));
- // If this is a trait, add all the trait item names to the trait info.
- let trait_item_def_ids = self.session.cstore.associated_item_def_ids(def_id);
- for trait_item_def_id in trait_item_def_ids {
- let trait_item_name = self.session.cstore.def_key(trait_item_def_id)
- .disambiguated_data.data.get_opt_name()
- .expect("opt_item_name returned None for trait");
- self.trait_item_map.insert((trait_item_name, def_id), false);
- }
- }
- Def::TyAlias(..) | Def::AssociatedTy(..) => {
- self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
- }
- Def::Struct(..) => {
- self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
+ for child in self.session.cstore.item_children(def_id) {
+ let ns = if let Def::AssociatedTy(..) = child.def { TypeNS } else { ValueNS };
+ let ident = Ident::with_empty_ctxt(child.name);
+ self.define(module, ident, ns, (child.def, ty::Visibility::Public,
+ DUMMY_SP, Mark::root()));
- // Record field names for error reporting.
- let field_names = self.session.cstore.struct_field_names(def_id);
- self.insert_field_names(def_id, field_names);
- }
- Def::StructCtor(..) => {
- self.define(parent, ident, ValueNS, (def, vis, 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);
+ self.trait_item_map.insert((def_id, child.name, ns), (child.def, has_self));
+ }
+ module.populated.set(true);
}
- Def::Union(..) => {
+ Def::Struct(..) | Def::Union(..) => {
self.define(parent, ident, TypeNS, (def, vis, DUMMY_SP, Mark::root()));
// Record field names for error reporting.
Def::Macro(..) => {
self.define(parent, ident, MacroNS, (def, vis, DUMMY_SP, Mark::root()));
}
- Def::Local(..) |
- Def::PrimTy(..) |
- Def::TyParam(..) |
- Def::Upvar(..) |
- Def::Label(..) |
- Def::SelfTy(..) |
- Def::Err => {
- bug!("unexpected definition: {:?}", def);
- }
+ _ => bug!("unexpected definition: {:?}", def)
}
}
let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX };
let name = self.session.cstore.crate_name(cnum);
let macros_only = self.session.cstore.dep_kind(cnum).macros_only();
+ let module_kind = ModuleKind::Def(Def::Mod(def_id), name);
let arenas = self.arenas;
*self.extern_crate_roots.entry((cnum, macros_only)).or_insert_with(|| {
- arenas.alloc_module(ModuleData {
- populated: Cell::new(false),
- ..ModuleData::new(None, ModuleKind::Def(Def::Mod(def_id), name))
- })
+ arenas.alloc_module(ModuleData::new(None, module_kind, def_id))
})
}
// Add the item to the trait info.
let item_def_id = self.resolver.definitions.local_def_id(item.id);
- let mut is_static_method = false;
- let (def, ns) = match item.node {
- TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS),
- TraitItemKind::Method(ref sig, _) => {
- is_static_method = !sig.decl.has_self();
- (Def::Method(item_def_id), ValueNS)
- }
- TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS),
+ let (def, ns, has_self) = match item.node {
+ TraitItemKind::Const(..) => (Def::AssociatedConst(item_def_id), ValueNS, false),
+ TraitItemKind::Method(ref sig, _) =>
+ (Def::Method(item_def_id), ValueNS, sig.decl.has_self()),
+ TraitItemKind::Type(..) => (Def::AssociatedTy(item_def_id), TypeNS, false),
TraitItemKind::Macro(_) => bug!(), // handled above
};
- self.resolver.trait_item_map.insert((item.ident.name, def_id), is_static_method);
+ self.resolver.trait_item_map.insert((def_id, item.ident.name, ns), (def, has_self));
let vis = ty::Visibility::Public;
self.resolver.define(parent, item.ident, ns, (def, vis, item.span, self.expansion));
```
"##,
+E0422: r##"
+You are trying to use an identifier that is either undefined or not a struct.
+Erroneous code example:
+``` compile_fail,E0422
+fn main () {
+ let x = Foo { x: 1, y: 2 };
+}
+```
+In this case, `Foo` is undefined, so it inherently isn't anything, and
+definitely not a struct.
+```compile_fail
+fn main () {
+ let foo = 1;
+ let x = foo { x: 1, y: 2 };
+}
+```
+In this case, `foo` is defined, but is not a struct, so Rust can't use it as
+one.
+"##,
+
E0423: r##"
A `struct` variant name was used like a function name.
// E0419, merged into 531
// E0420, merged into 532
// E0421, merged into 531
-// E0422, merged into 531/532
E0531, // unresolved pattern path kind `name`
// E0427, merged into 530
+ E0573,
+ E0574,
+ E0575,
+ E0576,
+ E0577,
+ E0578,
}
extern crate rustc;
use self::Namespace::*;
-use self::FallbackSuggestion::*;
use self::TypeParameters::*;
use self::RibKind::*;
use rustc::session::Session;
use rustc::lint;
use rustc::hir::def::*;
-use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, DefId};
+use rustc::hir::def_id::{CrateNum, CRATE_DEF_INDEX, LOCAL_CRATE, DefId};
use rustc::ty;
use rustc::hir::{Freevar, FreevarMap, TraitCandidate, TraitMap, GlobMap};
use rustc::util::nodemap::{NodeMap, NodeSet, FxHashMap, FxHashSet};
use syntax::ext::hygiene::{Mark, SyntaxContext};
-use syntax::ast::{self, FloatTy};
-use syntax::ast::{CRATE_NODE_ID, Name, NodeId, Ident, SpannedIdent, IntTy, UintTy};
+use syntax::ast::{self, Name, NodeId, Ident, SpannedIdent, FloatTy, IntTy, UintTy};
use syntax::ext::base::SyntaxExtension;
use syntax::ext::base::Determinacy::{Determined, Undetermined};
use syntax::symbol::{Symbol, keywords};
mod build_reduced_graph;
mod resolve_imports;
-enum SuggestionType {
- Macro(String),
- Function(Symbol),
- NotFound,
+/// A free importable items suggested in case of resolution failure.
+struct ImportSuggestion {
+ path: Path,
}
-/// Candidates for a name resolution failure
-struct SuggestedCandidates {
- name: String,
- candidates: Vec<Path>,
+/// A field or associated item from self type suggested in case of resolution failure.
+enum AssocSuggestion {
+ Field,
+ MethodWithSelf,
+ AssocItem,
}
enum ResolutionError<'a> {
OuterTypeParameterContext,
/// error E0403: the name is already used for a type parameter in this type parameter list
NameAlreadyUsedInTypeParameterList(Name, &'a Span),
- /// error E0404: is not a trait
- IsNotATrait(&'a str, &'a str),
- /// error E0405: use of undeclared trait name
- UndeclaredTraitName(&'a str, SuggestedCandidates),
/// error E0407: method is not a member of trait
MethodNotMemberOfTrait(Name, &'a str),
/// error E0437: type is not a member of trait
VariableNotBoundInPattern(Name, usize, usize),
/// error E0409: variable is bound with different mode in pattern #{} than in pattern #1
VariableBoundWithDifferentMode(Name, usize, Span),
- /// error E0411: use of `Self` outside of an impl or trait
- SelfUsedOutsideImplOrTrait,
- /// error E0412: use of undeclared
- UseOfUndeclared(&'a str, &'a str, SuggestedCandidates),
/// error E0415: identifier is bound more than once in this parameter list
IdentifierBoundMoreThanOnceInParameterList(&'a str),
/// error E0416: identifier is bound more than once in the same pattern
IdentifierBoundMoreThanOnceInSamePattern(&'a str),
- /// error E0423: is a struct variant name, but this expression uses it like a function name
- StructVariantUsedAsFunction(&'a str),
- /// error E0424: `self` is not available in a static method
- SelfNotAvailableInStaticMethod,
- /// error E0425: unresolved name
- UnresolvedName {
- path: &'a str,
- message: &'a str,
- context: UnresolvedNameContext<'a>,
- is_static_method: bool,
- is_field: bool,
- def: Def,
- },
/// error E0426: use of undeclared label
UndeclaredLabel(&'a str),
/// error E0429: `self` imports are only allowed within a { } list
AttemptToUseNonConstantValueInConstant,
/// error E0530: X bindings cannot shadow Ys
BindingShadowsSomethingUnacceptable(&'a str, Name, &'a NameBinding<'a>),
- /// error E0531: unresolved pattern path kind `name`
- PatPathUnresolved(&'a str, &'a Path),
- /// error E0532: expected pattern path kind, found another pattern path kind
- PatPathUnexpected(&'a str, &'a str, &'a Path),
-}
-
-/// Context of where `ResolutionError::UnresolvedName` arose.
-#[derive(Clone, PartialEq, Eq, Debug)]
-enum UnresolvedNameContext<'a> {
- /// `PathIsMod(parent)` indicates that a given path, used in
- /// expression context, actually resolved to a module rather than
- /// a value. The optional expression attached to the variant is the
- /// the parent of the erroneous path expression.
- PathIsMod(Option<&'a Expr>),
-
- /// `Other` means we have no extra information about the context
- /// of the unresolved name error. (Maybe we could eliminate all
- /// such cases; but for now, this is an information-free default.)
- Other,
}
-fn resolve_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
- span: syntax_pos::Span,
- resolution_error: ResolutionError<'c>) {
+fn resolve_error<'sess, 'a>(resolver: &'sess Resolver,
+ span: Span,
+ resolution_error: ResolutionError<'a>) {
resolve_struct_error(resolver, span, resolution_error).emit();
}
-fn resolve_struct_error<'b, 'a: 'b, 'c>(resolver: &'b Resolver<'a>,
- span: syntax_pos::Span,
- resolution_error: ResolutionError<'c>)
- -> DiagnosticBuilder<'a> {
+fn resolve_struct_error<'sess, 'a>(resolver: &'sess Resolver,
+ span: Span,
+ resolution_error: ResolutionError<'a>)
+ -> DiagnosticBuilder<'sess> {
match resolution_error {
ResolutionError::TypeParametersFromOuterFunction => {
let mut err = struct_span_err!(resolver.session,
err.span_label(span, &format!("already used"));
err.span_label(first_use_span.clone(), &format!("first use of `{}`", name));
err
-
- }
- ResolutionError::IsNotATrait(name, kind_name) => {
- let mut err = struct_span_err!(resolver.session,
- span,
- E0404,
- "`{}` is not a trait",
- name);
- err.span_label(span, &format!("expected trait, found {}", kind_name));
- err
- }
- ResolutionError::UndeclaredTraitName(name, candidates) => {
- let mut err = struct_span_err!(resolver.session,
- span,
- E0405,
- "trait `{}` is not in scope",
- name);
- show_candidates(&mut err, &candidates);
- err.span_label(span, &format!("`{}` is not in scope", name));
- err
}
ResolutionError::MethodNotMemberOfTrait(method, trait_) => {
let mut err = struct_span_err!(resolver.session,
err.span_label(first_binding_span, &format!("first binding"));
err
}
- ResolutionError::SelfUsedOutsideImplOrTrait => {
- let mut err = struct_span_err!(resolver.session,
- span,
- E0411,
- "use of `Self` outside of an impl or trait");
- err.span_label(span, &format!("used outside of impl or trait"));
- err
- }
- ResolutionError::UseOfUndeclared(kind, name, candidates) => {
- let mut err = struct_span_err!(resolver.session,
- span,
- E0412,
- "{} `{}` is undefined or not in scope",
- kind,
- name);
- show_candidates(&mut err, &candidates);
- err.span_label(span, &format!("undefined or not in scope"));
- err
- }
ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => {
let mut err = struct_span_err!(resolver.session,
span,
err.span_label(span, &format!("used in a pattern more than once"));
err
}
- ResolutionError::StructVariantUsedAsFunction(path_name) => {
- let mut err = struct_span_err!(resolver.session,
- span,
- E0423,
- "`{}` is the name of a struct or struct variant, but this expression \
- uses it like a function name",
- path_name);
- err.span_label(span, &format!("struct called like a function"));
- err
- }
- ResolutionError::SelfNotAvailableInStaticMethod => {
- let mut err = struct_span_err!(resolver.session,
- span,
- E0424,
- "`self` is not available in a static method");
- err.span_label(span, &format!("not available in static method"));
- err.note(&format!("maybe a `self` argument is missing?"));
- err
- }
- ResolutionError::UnresolvedName { path, message: msg, context, is_static_method,
- is_field, def } => {
- let mut err = struct_span_err!(resolver.session,
- span,
- E0425,
- "unresolved name `{}`",
- path);
- if msg != "" {
- err.span_label(span, &msg);
- } else {
- err.span_label(span, &format!("unresolved name"));
- }
-
- match context {
- UnresolvedNameContext::Other => {
- if msg.is_empty() && is_static_method && is_field {
- err.help("this is an associated function, you don't have access to \
- this type's fields or methods");
- }
- }
- UnresolvedNameContext::PathIsMod(parent) => {
- err.help(&match parent.map(|parent| &parent.node) {
- Some(&ExprKind::Field(_, ident)) => {
- format!("to reference an item from the `{module}` module, \
- use `{module}::{ident}`",
- module = path,
- ident = ident.node)
- }
- Some(&ExprKind::MethodCall(ident, ..)) => {
- format!("to call a function from the `{module}` module, \
- use `{module}::{ident}(..)`",
- module = path,
- ident = ident.node)
- }
- _ => {
- format!("{def} `{module}` cannot be used as an expression",
- def = def.kind_name(),
- module = path)
- }
- });
- }
- }
- err
- }
ResolutionError::UndeclaredLabel(name) => {
let mut err = struct_span_err!(resolver.session,
span,
err.span_label(binding.span, msg);
err
}
- ResolutionError::PatPathUnresolved(expected_what, path) => {
- struct_span_err!(resolver.session,
- span,
- E0531,
- "unresolved {} `{}`",
- expected_what,
- path)
- }
- ResolutionError::PatPathUnexpected(expected_what, found_what, path) => {
- struct_span_err!(resolver.session,
- span,
- E0532,
- "expected {}, found {} `{}`",
- expected_what,
- found_what,
- path)
- }
}
}
}
}
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+enum PathSource<'a> {
+ // Type paths `Path`.
+ Type,
+ // Trait paths in bounds or impls.
+ Trait,
+ // Expression paths `path`, with optional parent context.
+ Expr(Option<&'a ExprKind>),
+ // Paths in path patterns `Path`.
+ Pat,
+ // Paths in struct expressions and patterns `Path { .. }`.
+ Struct,
+ // Paths in tuple struct patterns `Path(..)`.
+ TupleStruct,
+ // `m::A::B` in `<T as m::A>::B::C`.
+ TraitItem(Namespace),
+ // Path in `pub(path)`
+ Visibility,
+ // Path in `use a::b::{...};`
+ ImportPrefix,
+}
+
+impl<'a> PathSource<'a> {
+ fn namespace(self) -> Namespace {
+ match self {
+ PathSource::Type | PathSource::Trait | PathSource::Struct |
+ PathSource::Visibility | PathSource::ImportPrefix => TypeNS,
+ PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct => ValueNS,
+ PathSource::TraitItem(ns) => ns,
+ }
+ }
+
+ fn global_by_default(self) -> bool {
+ match self {
+ PathSource::Visibility | PathSource::ImportPrefix => true,
+ PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
+ PathSource::Struct | PathSource::TupleStruct |
+ PathSource::Trait | PathSource::TraitItem(..) => false,
+ }
+ }
+
+ fn defer_to_typeck(self) -> bool {
+ match self {
+ PathSource::Type | PathSource::Expr(..) | PathSource::Pat |
+ PathSource::Struct | PathSource::TupleStruct => true,
+ PathSource::Trait | PathSource::TraitItem(..) |
+ PathSource::Visibility | PathSource::ImportPrefix => false,
+ }
+ }
+
+ fn descr_expected(self) -> &'static str {
+ match self {
+ PathSource::Type => "type",
+ PathSource::Trait => "trait",
+ PathSource::Pat => "unit struct/variant or constant",
+ PathSource::Struct => "struct, variant or union type",
+ PathSource::TupleStruct => "tuple struct/variant",
+ PathSource::Visibility => "module",
+ PathSource::ImportPrefix => "module or enum",
+ PathSource::TraitItem(ns) => match ns {
+ TypeNS => "associated type",
+ ValueNS => "method or associated constant",
+ MacroNS => bug!("associated macro"),
+ },
+ PathSource::Expr(parent) => match parent {
+ // "function" here means "anything callable" rather than `Def::Fn`,
+ // this is not precise but usually more helpful than just "value".
+ Some(&ExprKind::Call(..)) => "function",
+ _ => "value",
+ },
+ }
+ }
+
+ fn is_expected(self, def: Def) -> bool {
+ match self {
+ PathSource::Type => match def {
+ Def::Struct(..) | Def::Union(..) | Def::Enum(..) |
+ Def::Trait(..) | Def::TyAlias(..) | Def::AssociatedTy(..) |
+ Def::PrimTy(..) | Def::TyParam(..) | Def::SelfTy(..) => true,
+ _ => false,
+ },
+ PathSource::Trait => match def {
+ Def::Trait(..) => true,
+ _ => false,
+ },
+ PathSource::Expr(..) => match def {
+ Def::StructCtor(_, CtorKind::Const) | Def::StructCtor(_, CtorKind::Fn) |
+ Def::VariantCtor(_, CtorKind::Const) | Def::VariantCtor(_, CtorKind::Fn) |
+ Def::Const(..) | Def::Static(..) | Def::Local(..) | Def::Upvar(..) |
+ Def::Fn(..) | Def::Method(..) | Def::AssociatedConst(..) => true,
+ _ => false,
+ },
+ PathSource::Pat => match def {
+ Def::StructCtor(_, CtorKind::Const) |
+ Def::VariantCtor(_, CtorKind::Const) |
+ Def::Const(..) | Def::AssociatedConst(..) => true,
+ _ => false,
+ },
+ PathSource::TupleStruct => match def {
+ Def::StructCtor(_, CtorKind::Fn) | Def::VariantCtor(_, CtorKind::Fn) => true,
+ _ => false,
+ },
+ PathSource::Struct => match def {
+ Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
+ Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => true,
+ _ => false,
+ },
+ PathSource::TraitItem(ns) => match def {
+ Def::AssociatedConst(..) | Def::Method(..) if ns == ValueNS => true,
+ Def::AssociatedTy(..) if ns == TypeNS => true,
+ _ => false,
+ },
+ PathSource::ImportPrefix => match def {
+ Def::Mod(..) | Def::Enum(..) => true,
+ _ => false,
+ },
+ PathSource::Visibility => match def {
+ Def::Mod(..) => true,
+ _ => false,
+ },
+ }
+ }
+
+ fn error_code(self, has_unexpected_resolution: bool) -> &'static str {
+ __diagnostic_used!(E0404);
+ __diagnostic_used!(E0405);
+ __diagnostic_used!(E0412);
+ __diagnostic_used!(E0422);
+ __diagnostic_used!(E0423);
+ __diagnostic_used!(E0425);
+ __diagnostic_used!(E0531);
+ __diagnostic_used!(E0532);
+ __diagnostic_used!(E0573);
+ __diagnostic_used!(E0574);
+ __diagnostic_used!(E0575);
+ __diagnostic_used!(E0576);
+ __diagnostic_used!(E0577);
+ __diagnostic_used!(E0578);
+ match (self, has_unexpected_resolution) {
+ (PathSource::Trait, true) => "E0404",
+ (PathSource::Trait, false) => "E0405",
+ (PathSource::Type, true) => "E0573",
+ (PathSource::Type, false) => "E0412",
+ (PathSource::Struct, true) => "E0574",
+ (PathSource::Struct, false) => "E0422",
+ (PathSource::Expr(..), true) => "E0423",
+ (PathSource::Expr(..), false) => "E0425",
+ (PathSource::Pat, true) | (PathSource::TupleStruct, true) => "E0532",
+ (PathSource::Pat, false) | (PathSource::TupleStruct, false) => "E0531",
+ (PathSource::TraitItem(..), true) => "E0575",
+ (PathSource::TraitItem(..), false) => "E0576",
+ (PathSource::Visibility, true) | (PathSource::ImportPrefix, true) => "E0577",
+ (PathSource::Visibility, false) | (PathSource::ImportPrefix, false) => "E0578",
+ }
+ }
+}
+
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub enum Namespace {
TypeNS,
self.resolve_local(local);
}
fn visit_ty(&mut self, ty: &'tcx Ty) {
- self.resolve_type(ty);
+ if let TyKind::Path(ref qself, ref path) = ty.node {
+ self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
+ } else if let TyKind::ImplicitSelf = ty.node {
+ let self_ty = keywords::SelfType.ident();
+ let def = self.resolve_ident_in_lexical_scope(self_ty, TypeNS, Some(ty.span))
+ .map_or(Def::Err, |d| d.def());
+ self.record_def(ty.id, PathResolution::new(def));
+ } else if let TyKind::Array(ref element, ref length) = ty.node {
+ self.visit_ty(element);
+ self.with_constant_rib(|this| {
+ this.visit_expr(length);
+ });
+ return;
+ }
+ visit::walk_ty(self, ty);
}
fn visit_poly_trait_ref(&mut self,
tref: &'tcx ast::PolyTraitRef,
m: &'tcx ast::TraitBoundModifier) {
- let ast::Path { ref segments, span, global } = tref.trait_ref.path;
- let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
- let def = self.resolve_trait_reference(&path, global, None, span);
- self.record_def(tref.trait_ref.ref_id, def);
+ self.smart_resolve_path(tref.trait_ref.ref_id, None,
+ &tref.trait_ref.path, PathSource::Trait);
visit::walk_poly_trait_ref(self, tref, m);
}
fn visit_variant(&mut self,
pub type ErrorMessage = Option<(Span, String)>;
-enum FallbackSuggestion {
- NoSuggestion,
- Field,
- TraitItem,
- TraitMethod(String),
-}
-
#[derive(Copy, Clone)]
enum TypeParameters<'a, 'b> {
NoTypeParameters,
}
/// A definition along with the index of the rib it was found on
-#[derive(Copy, Clone)]
+#[derive(Copy, Clone, Debug)]
struct LocalDef {
ribs: Option<(Namespace, usize)>,
def: Def,
_ => None,
}
}
-}
-#[derive(Copy, Clone, PartialEq)]
-enum PathScope {
- Global,
- Lexical,
- Import,
+ fn def(self) -> Def {
+ match self {
+ LexicalScopeBinding::Item(binding) => binding.def(),
+ LexicalScopeBinding::Def(def) => def,
+ }
+ }
}
#[derive(Clone)]
parent: Option<Module<'a>>,
kind: ModuleKind,
- // The node id of the closest normal module (`mod`) ancestor (including this module).
- normal_ancestor_id: Option<NodeId>,
+ // The def id of the closest normal module (`mod`) ancestor (including this module).
+ normal_ancestor_id: DefId,
resolutions: RefCell<FxHashMap<(Ident, Namespace), &'a RefCell<NameResolution<'a>>>>,
legacy_macro_resolutions: RefCell<Vec<(Mark, Ident, Span)>>,
- macro_resolutions: RefCell<Vec<(Box<[Ident]>, PathScope, Span)>>,
+ macro_resolutions: RefCell<Vec<(Box<[Ident]>, Span)>>,
// Macro invocations that can expand into items in this module.
unresolved_invocations: RefCell<FxHashSet<Mark>>,
pub type Module<'a> = &'a ModuleData<'a>;
impl<'a> ModuleData<'a> {
- fn new(parent: Option<Module<'a>>, kind: ModuleKind) -> Self {
+ fn new(parent: Option<Module<'a>>, kind: ModuleKind, normal_ancestor_id: DefId) -> Self {
ModuleData {
parent: parent,
kind: kind,
- normal_ancestor_id: None,
+ normal_ancestor_id: normal_ancestor_id,
resolutions: RefCell::new(FxHashMap()),
legacy_macro_resolutions: RefCell::new(Vec::new()),
macro_resolutions: RefCell::new(Vec::new()),
glob_importers: RefCell::new(Vec::new()),
globs: RefCell::new((Vec::new())),
traits: RefCell::new(None),
- populated: Cell::new(true),
+ populated: Cell::new(normal_ancestor_id.is_local()),
}
}
}
fn is_local(&self) -> bool {
- self.normal_ancestor_id.is_some()
+ self.normal_ancestor_id.is_local()
}
}
prelude: Option<Module<'a>>,
- trait_item_map: FxHashMap<(Name, DefId), bool /* is static method? */>,
+ trait_item_map: FxHashMap<(DefId, Name, Namespace), (Def, bool /* has self */)>,
// Names of fields of an item `DefId` accessible with dot syntax.
// Used for hints during error reporting.
pub export_map: ExportMap,
pub trait_map: TraitMap,
- // A map from nodes to modules, both normal (`mod`) modules and anonymous modules.
+ // A map from nodes to anonymous modules.
// Anonymous modules are pseudo-modules that are implicitly created around items
// contained within blocks.
//
//
// There will be an anonymous module created around `g` with the ID of the
// entry block for `f`.
- module_map: NodeMap<Module<'a>>,
+ block_map: NodeMap<Module<'a>>,
+ module_map: FxHashMap<DefId, Module<'a>>,
extern_crate_roots: FxHashMap<(CrateNum, bool /* MacrosOnly? */), Module<'a>>,
pub make_glob_map: bool,
lexical_macro_resolutions: Vec<(Name, &'a Cell<LegacyScope<'a>>)>,
macro_map: FxHashMap<DefId, Rc<SyntaxExtension>>,
macro_exports: Vec<Export>,
+ pub whitelisted_legacy_custom_derives: Vec<Name>,
// Maps the `Mark` of an expansion to its containing module or block.
invocations: FxHashMap<Mark, &'a InvocationData<'a>>,
}
}
-impl<'a> ty::NodeIdTree for Resolver<'a> {
- fn is_descendant_of(&self, mut node: NodeId, ancestor: NodeId) -> bool {
- while node != ancestor {
- node = match self.module_map[&node].parent {
- Some(parent) => parent.normal_ancestor_id.unwrap(),
- None => return false,
- }
- }
- true
+impl<'a, 'b: 'a> ty::DefIdTree for &'a Resolver<'b> {
+ fn parent(self, id: DefId) -> Option<DefId> {
+ match id.krate {
+ LOCAL_CRATE => self.definitions.def_key(id.index).parent,
+ _ => self.session.cstore.def_key(id).parent,
+ }.map(|index| DefId { index: index, ..id })
}
}
impl<'a> hir::lowering::Resolver for Resolver<'a> {
fn resolve_hir_path(&mut self, path: &mut hir::Path, is_value: bool) {
let namespace = if is_value { ValueNS } else { TypeNS };
- let hir::Path { ref segments, span, global, ref mut def } = *path;
+ let hir::Path { ref segments, span, ref mut def } = *path;
let path: Vec<_> = segments.iter().map(|seg| Ident::with_empty_ctxt(seg.name)).collect();
- let scope = if global { PathScope::Global } else { PathScope::Lexical };
- match self.resolve_path(&path, scope, Some(namespace), Some(span)) {
+ match self.resolve_path(&path, Some(namespace), Some(span)) {
PathResult::Module(module) => *def = module.def().unwrap(),
PathResult::NonModule(path_res) if path_res.depth == 0 => *def = path_res.base_def,
- PathResult::NonModule(..) => match self.resolve_path(&path, scope, None, Some(span)) {
+ PathResult::NonModule(..) => match self.resolve_path(&path, None, Some(span)) {
PathResult::Failed(msg, _) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
}
crate_loader: &'a mut CrateLoader,
arenas: &'a ResolverArenas<'a>)
-> Resolver<'a> {
- let root_def = Def::Mod(DefId::local(CRATE_DEF_INDEX));
+ let root_def_id = DefId::local(CRATE_DEF_INDEX);
+ let root_module_kind = ModuleKind::Def(Def::Mod(root_def_id), keywords::Invalid.name());
let graph_root = arenas.alloc_module(ModuleData {
- normal_ancestor_id: Some(CRATE_NODE_ID),
no_implicit_prelude: attr::contains_name(&krate.attrs, "no_implicit_prelude"),
- ..ModuleData::new(None, ModuleKind::Def(root_def, keywords::Invalid.name()))
+ ..ModuleData::new(None, root_module_kind, root_def_id)
});
- let mut module_map = NodeMap();
- module_map.insert(CRATE_NODE_ID, graph_root);
+ let mut module_map = FxHashMap();
+ module_map.insert(DefId::local(CRATE_DEF_INDEX), graph_root);
let mut definitions = Definitions::new();
DefCollector::new(&mut definitions).collect_root();
export_map: NodeMap(),
trait_map: NodeMap(),
module_map: module_map,
+ block_map: NodeMap(),
extern_crate_roots: FxHashMap(),
make_glob_map: make_glob_map == MakeGlobMap::Yes,
macro_exports: Vec::new(),
invocations: invocations,
name_already_seen: FxHashMap(),
+ whitelisted_legacy_custom_derives: Vec::new(),
}
}
self.crate_loader.postprocess(krate);
}
- fn new_module(&self, parent: Module<'a>, kind: ModuleKind, local: bool) -> Module<'a> {
- self.arenas.alloc_module(ModuleData {
- normal_ancestor_id: if local { self.current_module.normal_ancestor_id } else { None },
- populated: Cell::new(local),
- ..ModuleData::new(Some(parent), kind)
- })
+ fn new_module(&self, parent: Module<'a>, kind: ModuleKind, normal_ancestor_id: DefId)
+ -> Module<'a> {
+ self.arenas.alloc_module(ModuleData::new(Some(parent), kind, normal_ancestor_id))
}
fn record_use(&mut self, ident: Ident, ns: Namespace, binding: &'a NameBinding<'a>, span: Span)
for i in (0 .. self.ribs[ns].len()).rev() {
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(if let Some(span) = record_used {
- self.adjust_local_def(LocalDef { ribs: Some((ns, i)), def: def }, span)
- } else {
- def
- }));
+ return Some(LexicalScopeBinding::Def(
+ self.adjust_local_def(LocalDef { ribs: Some((ns, i)), def: def }, record_used)
+ ));
}
if let ModuleRibKind(module) = self.ribs[ns][i].kind {
fn with_scope<F>(&mut self, id: NodeId, f: F)
where F: FnOnce(&mut Resolver)
{
+ let id = self.definitions.local_def_id(id);
let module = self.module_map.get(&id).cloned(); // clones a reference
if let Some(module) = module {
// Move down in the graph.
}
ItemKind::DefaultImpl(_, ref trait_ref) => {
- self.with_optional_trait_ref(Some(trait_ref), |_, _| {}, None);
+ self.with_optional_trait_ref(Some(trait_ref), |_, _| {});
}
ItemKind::Impl(.., ref generics, ref opt_trait_ref, ref self_type, ref impl_items) =>
self.resolve_implementation(generics,
ItemKind::Use(ref view_path) => {
match view_path.node {
- ast::ViewPathList(ref prefix, ref items) => {
- let path: Vec<_> =
- prefix.segments.iter().map(|seg| seg.identifier).collect();
- // Resolve prefix of an import with empty braces (issue #28388)
- if items.is_empty() && !prefix.segments.is_empty() {
- let (scope, span) = (PathScope::Import, prefix.span);
- // FIXME(#38012) This should be a module path, not anything in TypeNS.
- let result =
- self.resolve_path(&path, scope, Some(TypeNS), Some(span));
- let (def, msg) = match result {
- PathResult::Module(module) => (module.def().unwrap(), None),
- PathResult::NonModule(res) if res.depth == 0 =>
- (res.base_def, None),
- PathResult::NonModule(_) => {
- // Resolve a module path for better errors
- match self.resolve_path(&path, scope, None, Some(span)) {
- PathResult::Failed(msg, _) => (Def::Err, Some(msg)),
- _ => unreachable!(),
- }
- }
- PathResult::Indeterminate => unreachable!(),
- PathResult::Failed(msg, _) => (Def::Err, Some(msg)),
- };
- if let Some(msg) = msg {
- resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
- }
- self.record_def(item.id, PathResolution::new(def));
- }
+ ast::ViewPathList(ref prefix, ref items) if items.is_empty() => {
+ // Resolve prefix of an import with empty braces (issue #28388).
+ self.smart_resolve_path(item.id, None, prefix, PathSource::ImportPrefix);
}
_ => {}
}
self.ribs[ValueNS].pop();
}
- fn resolve_trait_reference(&mut self,
- path: &[Ident],
- global: bool,
- generics: Option<&Generics>,
- span: Span)
- -> PathResolution {
- let scope = if global { PathScope::Global } else { PathScope::Lexical };
- let def = match self.resolve_path(path, scope, None, Some(span)) {
- PathResult::Module(module) => Some(module.def().unwrap()),
- PathResult::NonModule(..) => return err_path_resolution(),
- PathResult::Failed(msg, false) => {
- resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
- return err_path_resolution();
- }
- _ => match self.resolve_path(path, scope, Some(TypeNS), None) {
- PathResult::NonModule(path_resolution) => Some(path_resolution.base_def),
- _ => None,
- },
- };
-
- if let Some(def) = def {
- if let Def::Trait(_) = def {
- return PathResolution::new(def);
- }
-
- let mut err = resolve_struct_error(self, span, {
- ResolutionError::IsNotATrait(&names_to_string(path), def.kind_name())
- });
- if let Some(generics) = generics {
- if let Some(span) = generics.span_for_name(&names_to_string(path)) {
- err.span_label(span, &"type parameter defined here");
- }
- }
-
- // If it's a typedef, give a note
- if let Def::TyAlias(..) = def {
- err.note(&format!("type aliases cannot be used for traits"));
- }
- err.emit();
- } else {
- // find possible candidates
- let is_trait = |def| match def { Def::Trait(_) => true, _ => false };
- let candidates = self.lookup_candidates(path.last().unwrap().name, TypeNS, is_trait);
-
- let path = names_to_string(path);
- resolve_error(self, span, ResolutionError::UndeclaredTraitName(&path, candidates));
- }
- err_path_resolution()
- }
-
fn with_current_self_type<T, F>(&mut self, self_type: &Ty, f: F) -> T
where F: FnOnce(&mut Resolver) -> T
{
result
}
- fn with_optional_trait_ref<T, F>(&mut self,
- opt_trait_ref: Option<&TraitRef>,
- f: F,
- generics: Option<&Generics>)
- -> T
+ fn with_optional_trait_ref<T, F>(&mut self, opt_trait_ref: Option<&TraitRef>, f: F) -> T
where F: FnOnce(&mut Resolver, Option<DefId>) -> T
{
let mut new_val = None;
let mut new_id = None;
if let Some(trait_ref) = opt_trait_ref {
- let ast::Path { ref segments, span, global } = trait_ref.path;
- let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
- let path_res = self.resolve_trait_reference(&path, global, generics, span);
- assert!(path_res.depth == 0);
- self.record_def(trait_ref.ref_id, path_res);
- if path_res.base_def != Def::Err {
- new_val = Some((path_res.base_def.def_id(), trait_ref.clone()));
- new_id = Some(path_res.base_def.def_id());
+ let def = self.smart_resolve_path(trait_ref.ref_id, None,
+ &trait_ref.path, PathSource::Trait).base_def;
+ if def != Def::Err {
+ new_val = Some((def.def_id(), trait_ref.clone()));
+ new_id = Some(def.def_id());
}
visit::walk_trait_ref(self, trait_ref);
}
// If this is a trait impl, ensure the const
// exists in trait
this.check_trait_item(impl_item.ident.name,
+ ValueNS,
impl_item.span,
|n, s| ResolutionError::ConstNotMemberOfTrait(n, s));
visit::walk_impl_item(this, impl_item);
// If this is a trait impl, ensure the method
// exists in trait
this.check_trait_item(impl_item.ident.name,
+ ValueNS,
impl_item.span,
|n, s| ResolutionError::MethodNotMemberOfTrait(n, s));
// If this is a trait impl, ensure the type
// exists in trait
this.check_trait_item(impl_item.ident.name,
+ TypeNS,
impl_item.span,
|n, s| ResolutionError::TypeNotMemberOfTrait(n, s));
}
});
});
- }, Some(&generics));
+ });
});
}
- fn check_trait_item<F>(&self, name: Name, span: Span, err: F)
+ fn check_trait_item<F>(&self, name: Name, ns: Namespace, span: Span, err: F)
where F: FnOnce(Name, &str) -> ResolutionError
{
// If there is a TraitRef in scope for an impl, then the method must be in the
// trait.
if let Some((did, ref trait_ref)) = self.current_trait_ref {
- if !self.trait_item_map.contains_key(&(name, did)) {
- let path_str = path_names_to_string(&trait_ref.path, 0);
+ if !self.trait_item_map.contains_key(&(did, name, ns)) {
+ let path_str = path_names_to_string(&trait_ref.path);
resolve_error(self, span, err(name, &path_str));
}
}
debug!("(resolving block) entering block");
// Move down in the graph, if there's an anonymous module rooted here.
let orig_module = self.current_module;
- let anonymous_module = self.module_map.get(&block.id).cloned(); // clones a reference
+ let anonymous_module = self.block_map.get(&block.id).cloned(); // clones a reference
let mut num_macro_definition_ribs = 0;
if let Some(anonymous_module) = anonymous_module {
debug!("(resolving block) leaving block");
}
- fn resolve_type(&mut self, ty: &Ty) {
- if let TyKind::Path(ref maybe_qself, ref path) = ty.node {
- // This is a path in the type namespace. Walk through scopes looking for it.
- if let Some(def) =
- self.resolve_possibly_assoc_item(ty.id, maybe_qself.as_ref(), path, TypeNS) {
- match def.base_def {
- Def::Mod(..) if def.depth == 0 => {
- self.session.span_err(path.span, "expected type, found module");
- self.record_def(ty.id, err_path_resolution());
- }
- _ => {
- // Write the result into the def map.
- debug!("(resolving type) writing resolution for `{}` (id {}) = {:?}",
- path_names_to_string(path, 0), ty.id, def);
- self.record_def(ty.id, def);
- }
- }
- } else {
- self.record_def(ty.id, err_path_resolution());
- // Keep reporting some errors even if they're ignored above.
- let kind = if maybe_qself.is_some() { "associated type" } else { "type name" };
- let is_invalid_self_type_name = {
- path.segments.len() > 0 &&
- maybe_qself.is_none() &&
- path.segments[0].identifier.name == keywords::SelfType.name()
- };
-
- if is_invalid_self_type_name {
- resolve_error(self, ty.span, ResolutionError::SelfUsedOutsideImplOrTrait);
- } else {
- let type_name = path.segments.last().unwrap().identifier.name;
- let candidates = self.lookup_candidates(type_name, TypeNS, |def| {
- match def {
- Def::Trait(_) |
- Def::Enum(_) |
- Def::Struct(_) |
- Def::Union(_) |
- Def::TyAlias(_) => true,
- _ => false,
- }
- });
-
- let name = &path_names_to_string(path, 0);
- let error = ResolutionError::UseOfUndeclared(kind, name, candidates);
- resolve_error(self, ty.span, error);
- }
- }
- }
- // Resolve embedded types.
- visit::walk_ty(self, ty);
- }
-
fn fresh_binding(&mut self,
ident: &SpannedIdent,
pat_id: NodeId,
PathResolution::new(def)
}
- fn resolve_pattern_path<ExpectedFn>(&mut self,
- pat_id: NodeId,
- qself: Option<&QSelf>,
- path: &Path,
- namespace: Namespace,
- expected_fn: ExpectedFn,
- expected_what: &str)
- where ExpectedFn: FnOnce(Def) -> bool
- {
- let resolution = if let Some(resolution) = self.resolve_possibly_assoc_item(pat_id,
- qself, path, namespace) {
- if resolution.depth == 0 {
- if expected_fn(resolution.base_def) || resolution.base_def == Def::Err {
- resolution
- } else {
- resolve_error(
- self,
- path.span,
- ResolutionError::PatPathUnexpected(expected_what,
- resolution.kind_name(), path)
- );
- err_path_resolution()
- }
- } else {
- // Not fully resolved associated item `T::A::B` or `<T as Tr>::A::B`
- // or `<T>::A::B`. If `B` should be resolved in value namespace then
- // it needs to be added to the trait map.
- if namespace == ValueNS {
- let item_name = path.segments.last().unwrap().identifier.name;
- let traits = self.get_traits_containing_item(item_name);
- self.trait_map.insert(pat_id, traits);
- }
- resolution
- }
- } else {
- let error = ResolutionError::PatPathUnresolved(expected_what, path);
- resolve_error(self, path.span, error);
- err_path_resolution()
- };
-
- self.record_def(pat_id, resolution);
- }
-
- fn resolve_struct_path(&mut self, node_id: NodeId, path: &Path) {
- // Resolution logic is equivalent for expressions and patterns,
- // reuse `resolve_pattern_path` for both.
- self.resolve_pattern_path(node_id, None, path, TypeNS, |def| {
- match def {
- Def::Struct(..) | Def::Union(..) | Def::Variant(..) |
- Def::TyAlias(..) | Def::AssociatedTy(..) | Def::SelfTy(..) => true,
- _ => false,
- }
- }, "struct, variant or union type");
- }
-
fn resolve_pattern(&mut self,
pat: &Pat,
pat_src: PatternSource,
}
PatKind::TupleStruct(ref path, ..) => {
- self.resolve_pattern_path(pat.id, None, path, ValueNS, |def| {
- match def {
- Def::StructCtor(_, CtorKind::Fn) |
- Def::VariantCtor(_, CtorKind::Fn) => true,
- _ => false,
- }
- }, "tuple struct/variant");
+ self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct);
}
PatKind::Path(ref qself, ref path) => {
- self.resolve_pattern_path(pat.id, qself.as_ref(), path, ValueNS, |def| {
- match def {
- Def::StructCtor(_, CtorKind::Const) |
- Def::VariantCtor(_, CtorKind::Const) |
- Def::Const(..) | Def::AssociatedConst(..) => true,
- _ => false,
- }
- }, "unit struct/variant or constant");
+ self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat);
}
PatKind::Struct(ref path, ..) => {
- self.resolve_struct_path(pat.id, path);
+ self.smart_resolve_path(pat.id, None, path, PathSource::Struct);
}
_ => {}
visit::walk_pat(self, pat);
}
- /// Handles paths that may refer to associated items
- fn resolve_possibly_assoc_item(&mut self,
+ // High-level and context dependent path resolution routine.
+ // Resolves the path and records the resolution into definition map.
+ // If resolution fails tries several techniques to find likely
+ // resolution candidates, suggest imports or other help, and report
+ // errors in user friendly way.
+ fn smart_resolve_path(&mut self,
+ id: NodeId,
+ qself: Option<&QSelf>,
+ path: &Path,
+ source: PathSource)
+ -> PathResolution {
+ let segments = &path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>();
+ self.smart_resolve_path_fragment(id, qself, segments, path.span, source)
+ }
+
+ fn smart_resolve_path_fragment(&mut self,
id: NodeId,
- maybe_qself: Option<&QSelf>,
- path: &Path,
- ns: Namespace)
- -> Option<PathResolution> {
- let ast::Path { ref segments, global, span } = *path;
- let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
- let scope = if global { PathScope::Global } else { PathScope::Lexical };
-
- if let Some(qself) = maybe_qself {
+ qself: Option<&QSelf>,
+ path: &[Ident],
+ span: Span,
+ source: PathSource)
+ -> PathResolution {
+ let ns = source.namespace();
+ let is_expected = &|def| source.is_expected(def);
+
+ // Base error is amended with one short label and possibly some longer helps/notes.
+ let report_errors = |this: &mut Self, def: Option<Def>| {
+ // Make the base error.
+ let expected = source.descr_expected();
+ let path_str = names_to_string(path);
+ let code = source.error_code(def.is_some());
+ let base_msg = if let Some(def) = def {
+ format!("expected {}, found {} `{}`", expected, def.kind_name(), path_str)
+ } else {
+ format!("unresolved {} `{}`", expected, path_str)
+ };
+ let mut err = this.session.struct_span_err_with_code(span, &base_msg, code);
+
+ // Emit special messages for unresolved `Self` and `self`.
+ if is_self_type(path, ns) {
+ __diagnostic_used!(E0411);
+ err.code("E0411".into());
+ err.span_label(span, &format!("`Self` is only available in traits and impls"));
+ return err;
+ }
+ if is_self_value(path, ns) {
+ __diagnostic_used!(E0424);
+ err.code("E0424".into());
+ err.span_label(span, &format!("`self` value is only available in \
+ methods with `self` parameter"));
+ return err;
+ }
+
+ // Try to lookup the name in more relaxed fashion for better error reporting.
+ let name = path.last().unwrap().name;
+ let candidates = this.lookup_import_candidates(name, ns, is_expected);
+ if !candidates.is_empty() {
+ // Report import candidates as help and proceed searching for labels.
+ show_candidates(&mut err, &candidates, def.is_some());
+ }
+ if path.len() == 1 && this.self_type_is_available() {
+ if let Some(candidate) = this.lookup_assoc_candidate(name, ns, is_expected) {
+ let self_is_available = this.self_value_is_available(path[0].ctxt);
+ match candidate {
+ AssocSuggestion::Field => {
+ err.span_label(span, &format!("did you mean `self.{}`?", path_str));
+ if !self_is_available {
+ err.span_label(span, &format!("`self` value is only available in \
+ methods with `self` parameter"));
+ }
+ }
+ AssocSuggestion::MethodWithSelf if self_is_available => {
+ err.span_label(span, &format!("did you mean `self.{}(...)`?",
+ path_str));
+ }
+ AssocSuggestion::MethodWithSelf | AssocSuggestion::AssocItem => {
+ err.span_label(span, &format!("did you mean `Self::{}`?", path_str));
+ }
+ }
+ return err;
+ }
+ }
+
+ // Try context dependent help if relaxed lookup didn't work.
+ if let Some(def) = def {
+ match (def, source) {
+ (Def::Macro(..), _) => {
+ err.span_label(span, &format!("did you mean `{}!(...)`?", path_str));
+ return err;
+ }
+ (Def::TyAlias(..), PathSource::Trait) => {
+ err.span_label(span, &format!("type aliases cannot be used for traits"));
+ return err;
+ }
+ (Def::Mod(..), PathSource::Expr(Some(parent))) => match *parent {
+ ExprKind::Field(_, ident) => {
+ err.span_label(span, &format!("did you mean `{}::{}`?",
+ path_str, ident.node));
+ return err;
+ }
+ ExprKind::MethodCall(ident, ..) => {
+ err.span_label(span, &format!("did you mean `{}::{}(...)`?",
+ path_str, ident.node));
+ return err;
+ }
+ _ => {}
+ },
+ _ if ns == ValueNS && is_struct_like(def) => {
+ err.span_label(span, &format!("did you mean `{} {{ /* fields */ }}`?",
+ path_str));
+ return err;
+ }
+ _ => {}
+ }
+ }
+
+ // Try Levenshtein if nothing else worked.
+ if path.len() == 1 {
+ if let Some(candidate) = this.lookup_typo_candidate(name, ns, is_expected) {
+ err.span_label(span, &format!("did you mean `{}`?", candidate));
+ return err;
+ }
+ }
+
+ // Fallback labels.
+ if def.is_some() {
+ err.span_label(span, &format!("not a {}", expected));
+ } else {
+ err.span_label(span, &format!("no resolution found"));
+ }
+ err
+ };
+ let report_errors = |this: &mut Self, def: Option<Def>| {
+ report_errors(this, def).emit();
+ err_path_resolution()
+ };
+
+ let resolution = match self.resolve_qpath_anywhere(id, qself, path, ns, span,
+ source.defer_to_typeck(),
+ source.global_by_default()) {
+ Some(resolution) if resolution.depth == 0 => {
+ if is_expected(resolution.base_def) || resolution.base_def == Def::Err {
+ resolution
+ } else {
+ report_errors(self, Some(resolution.base_def))
+ }
+ }
+ Some(resolution) if source.defer_to_typeck() => {
+ // Not fully resolved associated item `T::A::B` or `<T as Tr>::A::B`
+ // or `<T>::A::B`. If `B` should be resolved in value namespace then
+ // it needs to be added to the trait map.
+ if ns == ValueNS {
+ let item_name = path.last().unwrap().name;
+ let traits = self.get_traits_containing_item(item_name, ns);
+ self.trait_map.insert(id, traits);
+ }
+ resolution
+ }
+ _ => report_errors(self, None)
+ };
+
+ if let PathSource::TraitItem(..) = source {} else {
+ // Avoid recording definition of `A::B` in `<T as A>::B::C`.
+ self.record_def(id, resolution);
+ }
+ resolution
+ }
+
+ fn self_type_is_available(&mut self) -> bool {
+ let binding = self.resolve_ident_in_lexical_scope(keywords::SelfType.ident(), TypeNS, None);
+ if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
+ }
+
+ fn self_value_is_available(&mut self, ctxt: SyntaxContext) -> bool {
+ let ident = Ident { name: keywords::SelfValue.name(), ctxt: ctxt };
+ let binding = self.resolve_ident_in_lexical_scope(ident, ValueNS, None);
+ if let Some(LexicalScopeBinding::Def(def)) = binding { def != Def::Err } else { false }
+ }
+
+ // Resolve in alternative namespaces if resolution in the primary namespace fails.
+ fn resolve_qpath_anywhere(&mut self,
+ id: NodeId,
+ qself: Option<&QSelf>,
+ path: &[Ident],
+ primary_ns: Namespace,
+ span: Span,
+ defer_to_typeck: bool,
+ global_by_default: bool)
+ -> Option<PathResolution> {
+ let mut fin_res = None;
+ // FIXME: can't resolve paths in macro namespace yet, macros are
+ // processed by the little special hack below.
+ for (i, ns) in [primary_ns, TypeNS, ValueNS, /*MacroNS*/].iter().cloned().enumerate() {
+ if i == 0 || ns != primary_ns {
+ match self.resolve_qpath(id, qself, path, ns, span, global_by_default) {
+ // If defer_to_typeck, then resolution > no resolution,
+ // otherwise full resolution > partial resolution > no resolution.
+ Some(res) if res.depth == 0 || defer_to_typeck => return Some(res),
+ res => if fin_res.is_none() { fin_res = res },
+ };
+ }
+ }
+ if primary_ns != MacroNS && path.len() == 1 &&
+ 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))));
+ }
+ fin_res
+ }
+
+ /// Handles paths that may refer to associated items.
+ fn resolve_qpath(&mut self,
+ id: NodeId,
+ qself: Option<&QSelf>,
+ path: &[Ident],
+ ns: Namespace,
+ span: Span,
+ global_by_default: bool)
+ -> Option<PathResolution> {
+ if let Some(qself) = qself {
if qself.position == 0 {
// FIXME: Create some fake resolution that can't possibly be a type.
return Some(PathResolution {
- base_def: Def::Mod(self.definitions.local_def_id(ast::CRATE_NODE_ID)),
+ base_def: Def::Mod(DefId::local(CRATE_DEF_INDEX)),
depth: path.len(),
});
}
- // Make sure the trait is valid.
- self.resolve_trait_reference(&path[..qself.position], global, None, span);
+ // Make sure `A::B` in `<T as A>::B::C` is a trait item.
+ let ns = if qself.position + 1 == path.len() { ns } else { TypeNS };
+ let mut res = self.smart_resolve_path_fragment(id, None, &path[..qself.position + 1],
+ span, PathSource::TraitItem(ns));
+ if res.base_def != Def::Err {
+ res.depth += path.len() - qself.position - 1;
+ }
+ return Some(res);
}
- let result = match self.resolve_path(&path, scope, Some(ns), Some(span)) {
- PathResult::NonModule(path_res) => match path_res.base_def {
- Def::Trait(..) if maybe_qself.is_some() => return None,
- _ => path_res,
- },
+ let result = match self.resolve_path(&path, Some(ns), Some(span)) {
+ PathResult::NonModule(path_res) => path_res,
PathResult::Module(module) if !module.is_normal() => {
PathResolution::new(module.def().unwrap())
}
// Such behavior is required for backward compatibility.
// The same fallback is used when `a` resolves to nothing.
PathResult::Module(..) | PathResult::Failed(..)
- if scope == PathScope::Lexical && (ns == TypeNS || path.len() > 1) &&
+ if (ns == TypeNS || path.len() > 1) &&
self.primitive_type_table.primitive_types.contains_key(&path[0].name) => {
PathResolution {
base_def: Def::PrimTy(self.primitive_type_table.primitive_types[&path[0].name]),
- depth: segments.len() - 1,
+ depth: path.len() - 1,
}
}
PathResult::Module(module) => PathResolution::new(module.def().unwrap()),
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
err_path_resolution()
}
- _ => return None,
+ PathResult::Failed(..) => return None,
+ PathResult::Indeterminate => bug!("indetermined path result in resolve_qpath"),
};
- if path.len() == 1 || result.base_def == Def::Err {
+ if path.len() == 1 || global_by_default || result.base_def == Def::Err {
return Some(result);
}
let unqualified_result = {
- match self.resolve_path(&[*path.last().unwrap()], PathScope::Lexical, Some(ns), None) {
+ match self.resolve_path(&[*path.last().unwrap()], Some(ns), None) {
PathResult::NonModule(path_res) => path_res.base_def,
PathResult::Module(module) => module.def().unwrap(),
_ => return Some(result),
fn resolve_path(&mut self,
path: &[Ident],
- scope: PathScope,
opt_ns: Option<Namespace>, // `None` indicates a module path
record_used: Option<Span>)
-> PathResult<'a> {
- let (mut module, allow_self) = match scope {
- PathScope::Lexical => (None, true),
- PathScope::Import => (Some(self.graph_root), true),
- PathScope::Global => (Some(self.graph_root), false),
- };
- let mut allow_super = allow_self;
+ let mut module = None;
+ let mut allow_super = true;
for (i, &ident) in path.iter().enumerate() {
let is_last = i == path.len() - 1;
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
- if i == 0 && allow_self && ns == TypeNS && ident.name == keywords::SelfValue.name() {
- module = Some(self.module_map[&self.current_module.normal_ancestor_id.unwrap()]);
- continue
- } else if i == 0 && allow_self && ns == TypeNS && ident.name == "$crate" {
- module = Some(self.resolve_crate_var(ident.ctxt));
+ if i == 0 && ns == TypeNS && ident.name == keywords::SelfValue.name() {
+ module = Some(self.module_map[&self.current_module.normal_ancestor_id]);
continue
} else if allow_super && ns == TypeNS && ident.name == keywords::Super.name() {
let current_module = if i == 0 { self.current_module } else { module.unwrap() };
- let self_module = self.module_map[¤t_module.normal_ancestor_id.unwrap()];
+ let self_module = self.module_map[¤t_module.normal_ancestor_id];
if let Some(parent) = self_module.parent {
- module = Some(self.module_map[&parent.normal_ancestor_id.unwrap()]);
+ module = Some(self.module_map[&parent.normal_ancestor_id]);
continue
} else {
let msg = "There are too many initial `super`s.".to_string();
}
allow_super = false;
+ if i == 0 && ns == TypeNS && ident.name == keywords::CrateRoot.name() {
+ module = Some(self.graph_root);
+ continue
+ } else if i == 0 && ns == TypeNS && ident.name == "$crate" {
+ module = Some(self.resolve_crate_var(ident.ctxt));
+ continue
+ }
+
let binding = if let Some(module) = module {
self.resolve_ident_in_module(module, ident, ns, false, record_used)
} else if opt_ns == Some(MacroNS) {
let msg = if module.and_then(ModuleData::def) == self.graph_root.def() {
let is_mod = |def| match def { Def::Mod(..) => true, _ => false };
let mut candidates =
- self.lookup_candidates(ident.name, TypeNS, is_mod).candidates;
- candidates.sort_by_key(|path| (path.segments.len(), path.to_string()));
+ self.lookup_import_candidates(ident.name, TypeNS, is_mod);
+ candidates.sort_by_key(|c| (c.path.segments.len(), c.path.to_string()));
if let Some(candidate) = candidates.get(0) {
- format!("Did you mean `{}`?", candidate)
+ format!("Did you mean `{}`?", candidate.path)
} else {
format!("Maybe a missing `extern crate {};`?", ident)
}
}
}
- PathResult::Module(module.unwrap())
+ PathResult::Module(module.unwrap_or(self.graph_root))
}
// Resolve a local definition, potentially adjusting for closures.
- fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Def {
+ 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;
match def {
Def::Upvar(..) => {
- span_bug!(span, "unexpected {:?} in bindings", def)
+ span_bug!(record_used.unwrap_or(DUMMY_SP), "unexpected {:?} in bindings", def)
}
Def::Local(def_id) => {
for rib in ribs {
.entry(function_id)
.or_insert_with(|| vec![]);
let depth = vec.len();
- vec.push(Freevar {
- def: prev_def,
- span: span,
- });
-
def = Def::Upvar(def_id, depth, function_id);
- seen.insert(node_id, depth);
+
+ if let Some(span) = record_used {
+ vec.push(Freevar {
+ def: prev_def,
+ span: span,
+ });
+ seen.insert(node_id, depth);
+ }
}
ItemRibKind | MethodRibKind(_) => {
// This was an attempt to access an upvar inside a
// named function item. This is not allowed, so we
// report an error.
- resolve_error(self,
- span,
- ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
+ if let Some(span) = record_used {
+ resolve_error(self, span,
+ ResolutionError::CannotCaptureDynamicEnvironmentInFnItem);
+ }
return Def::Err;
}
ConstantItemRibKind => {
// Still doesn't deal with upvars
- resolve_error(self,
- span,
- ResolutionError::AttemptToUseNonConstantValueInConstant);
+ if let Some(span) = record_used {
+ resolve_error(self, span,
+ ResolutionError::AttemptToUseNonConstantValueInConstant);
+ }
return Def::Err;
}
}
ItemRibKind => {
// This was an attempt to use a type parameter outside
// its scope.
-
- resolve_error(self,
- span,
- ResolutionError::TypeParametersFromOuterFunction);
+ if let Some(span) = record_used {
+ resolve_error(self, span,
+ ResolutionError::TypeParametersFromOuterFunction);
+ }
return Def::Err;
}
ConstantItemRibKind => {
// see #9186
- resolve_error(self, span, ResolutionError::OuterTypeParameterContext);
+ if let Some(span) = record_used {
+ resolve_error(self, span,
+ ResolutionError::OuterTypeParameterContext);
+ }
return Def::Err;
}
}
result
}
- fn find_fallback_in_self_type(&mut self, name: Name) -> FallbackSuggestion {
+ fn lookup_assoc_candidate<FilterFn>(&mut self,
+ name: Name,
+ ns: Namespace,
+ filter_fn: FilterFn)
+ -> Option<AssocSuggestion>
+ where FilterFn: Fn(Def) -> bool
+ {
fn extract_node_id(t: &Ty) -> Option<NodeId> {
match t.node {
TyKind::Path(None, _) => Some(t.id),
}
}
- if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
- // Look for a field with the same name in the current self_type.
- if let Some(resolution) = self.def_map.get(&node_id) {
- match resolution.base_def {
- Def::Struct(did) | Def::Union(did) if resolution.depth == 0 => {
- if let Some(field_names) = self.field_names.get(&did) {
- if field_names.iter().any(|&field_name| name == field_name) {
- return Field;
+ // Fields are generally expected in the same contexts as locals.
+ if filter_fn(Def::Local(DefId::local(CRATE_DEF_INDEX))) {
+ if let Some(node_id) = self.current_self_type.as_ref().and_then(extract_node_id) {
+ // Look for a field with the same name in the current self_type.
+ if let Some(resolution) = self.def_map.get(&node_id) {
+ match resolution.base_def {
+ Def::Struct(did) | Def::Union(did) if resolution.depth == 0 => {
+ if let Some(field_names) = self.field_names.get(&did) {
+ if field_names.iter().any(|&field_name| name == field_name) {
+ return Some(AssocSuggestion::Field);
+ }
}
}
+ _ => {}
}
- _ => {}
}
}
}
- // Look for a method in the current trait.
- if let Some((trait_did, ref trait_ref)) = self.current_trait_ref {
- if let Some(&is_static_method) = self.trait_item_map.get(&(name, trait_did)) {
- if is_static_method {
- return TraitMethod(path_names_to_string(&trait_ref.path, 0));
- } else {
- return TraitItem;
+ // Look for associated items in the current trait.
+ if let Some((trait_did, _)) = self.current_trait_ref {
+ if let Some(&(def, has_self)) = self.trait_item_map.get(&(trait_did, name, ns)) {
+ if filter_fn(def) {
+ return Some(if has_self {
+ AssocSuggestion::MethodWithSelf
+ } else {
+ AssocSuggestion::AssocItem
+ });
}
}
}
- NoSuggestion
+ None
}
- fn find_best_match(&mut self, name: &str) -> SuggestionType {
- if let Some(macro_name) = self.macro_names.iter().find(|&n| n == &name) {
- return SuggestionType::Macro(format!("{}!", macro_name));
+ fn lookup_typo_candidate<FilterFn>(&mut self,
+ name: Name,
+ ns: Namespace,
+ filter_fn: FilterFn)
+ -> Option<Name>
+ where FilterFn: Fn(Def) -> bool
+ {
+ // FIXME: bindings in ribs provide quite modest set of candidates,
+ // extend it with other names in scope.
+ let names = self.ribs[ns].iter().rev().flat_map(|rib| {
+ rib.bindings.iter().filter_map(|(ident, def)| {
+ if filter_fn(*def) { Some(&ident.name) } else { None }
+ })
+ });
+ match find_best_match_for_name(names, &name.as_str(), None) {
+ Some(found) if found != name => Some(found),
+ _ => None,
}
-
- let names = self.ribs[ValueNS]
- .iter()
- .rev()
- .flat_map(|rib| rib.bindings.keys().map(|ident| &ident.name));
-
- if let Some(found) = find_best_match_for_name(names, name, None) {
- if found != name {
- return SuggestionType::Function(found);
- }
- } SuggestionType::NotFound
}
fn resolve_labeled_block(&mut self, label: Option<SpannedIdent>, id: NodeId, block: &Block) {
}
}
- fn resolve_expr(&mut self, expr: &Expr, parent: Option<&Expr>) {
+ 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.
// Next, resolve the node.
match expr.node {
- ExprKind::Path(ref maybe_qself, ref path) => {
- // This is a local path in the value namespace. Walk through
- // scopes looking for it.
- if let Some(path_res) = self.resolve_possibly_assoc_item(expr.id,
- maybe_qself.as_ref(), path, ValueNS) {
- // Check if struct variant
- let is_struct_variant = match path_res.base_def {
- Def::VariantCtor(_, CtorKind::Fictive) => true,
- _ => false,
- };
- if is_struct_variant {
- let path_name = path_names_to_string(path, 0);
-
- let mut err = resolve_struct_error(self,
- expr.span,
- ResolutionError::StructVariantUsedAsFunction(&path_name));
-
- let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
- path_name);
- err.help(&msg);
- err.emit();
- self.record_def(expr.id, err_path_resolution());
- } else {
- // Write the result into the def map.
- debug!("(resolving expr) resolved `{}`",
- path_names_to_string(path, 0));
-
- // Partial resolutions will need the set of traits in scope,
- // so they can be completed during typeck.
- if path_res.depth != 0 {
- let method_name = path.segments.last().unwrap().identifier.name;
- let traits = self.get_traits_containing_item(method_name);
- self.trait_map.insert(expr.id, traits);
- }
-
- self.record_def(expr.id, path_res);
- }
- } else {
- // Be helpful if the name refers to a struct
- let path_name = path_names_to_string(path, 0);
- let ast::Path { ref segments, global, .. } = *path;
- let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
- let scope = if global { PathScope::Global } else { PathScope::Lexical };
- let type_res = match self.resolve_path(&path, scope, Some(TypeNS), None) {
- PathResult::NonModule(type_res) => Some(type_res),
- _ => None,
- };
-
- self.record_def(expr.id, err_path_resolution());
-
- if let Some(Def::Struct(..)) = type_res.map(|r| r.base_def) {
- let error_variant =
- ResolutionError::StructVariantUsedAsFunction(&path_name);
- let mut err = resolve_struct_error(self, expr.span, error_variant);
-
- let msg = format!("did you mean to write: `{} {{ /* fields */ }}`?",
- path_name);
-
- err.help(&msg);
- err.emit();
- } else {
- // Keep reporting some errors even if they're ignored above.
- let mut method_scope = false;
- let mut is_static = false;
- self.ribs[ValueNS].iter().rev().all(|rib| {
- method_scope = match rib.kind {
- MethodRibKind(is_static_) => {
- is_static = is_static_;
- true
- }
- ItemRibKind | ConstantItemRibKind => false,
- _ => return true, // Keep advancing
- };
- false // Stop advancing
- });
-
- if method_scope && keywords::SelfValue.name() == &*path_name {
- let error = ResolutionError::SelfNotAvailableInStaticMethod;
- resolve_error(self, expr.span, error);
- } else {
- let fallback =
- self.find_fallback_in_self_type(path.last().unwrap().name);
- let (mut msg, is_field) = match fallback {
- NoSuggestion => {
- // limit search to 5 to reduce the number
- // of stupid suggestions
- (match self.find_best_match(&path_name) {
- SuggestionType::Macro(s) => {
- format!("the macro `{}`", s)
- }
- SuggestionType::Function(s) => format!("`{}`", s),
- SuggestionType::NotFound => "".to_string(),
- }, false)
- }
- Field => {
- (if is_static && method_scope {
- "".to_string()
- } else {
- format!("`self.{}`", path_name)
- }, true)
- }
- TraitItem => (format!("to call `self.{}`", path_name), false),
- TraitMethod(path_str) =>
- (format!("to call `{}::{}`", path_str, path_name), false),
- };
-
- let mut context = UnresolvedNameContext::Other;
- let mut def = Def::Err;
- if !msg.is_empty() {
- msg = format!("did you mean {}?", msg);
- } else {
- // we display a help message if this is a module
- if let PathResult::Module(module) =
- self.resolve_path(&path, scope, None, None) {
- def = module.def().unwrap();
- context = UnresolvedNameContext::PathIsMod(parent);
- }
- }
-
- let error = ResolutionError::UnresolvedName {
- path: &path_name,
- message: &msg,
- context: context,
- is_static_method: method_scope && is_static,
- is_field: is_field,
- def: def,
- };
- resolve_error(self, expr.span, error);
- }
- }
- }
-
+ ExprKind::Path(ref qself, ref path) => {
+ self.smart_resolve_path(expr.id, qself.as_ref(), path, PathSource::Expr(parent));
visit::walk_expr(self, expr);
}
ExprKind::Struct(ref path, ..) => {
- self.resolve_struct_path(expr.id, path);
-
+ self.smart_resolve_path(expr.id, None, path, PathSource::Struct);
visit::walk_expr(self, expr);
}
self.ribs[ValueNS].pop();
}
+ // Equivalent to `visit::walk_expr` + passing some context to children.
ExprKind::Field(ref subexpression, _) => {
- self.resolve_expr(subexpression, Some(expr));
+ self.resolve_expr(subexpression, Some(&expr.node));
}
ExprKind::MethodCall(_, ref types, ref arguments) => {
let mut arguments = arguments.iter();
- self.resolve_expr(arguments.next().unwrap(), Some(expr));
+ self.resolve_expr(arguments.next().unwrap(), Some(&expr.node));
for argument in arguments {
self.resolve_expr(argument, None);
}
}
}
+ ExprKind::Repeat(ref element, ref count) => {
+ self.visit_expr(element);
+ self.with_constant_rib(|this| {
+ this.visit_expr(count);
+ });
+ }
+ ExprKind::Call(ref callee, ref arguments) => {
+ self.resolve_expr(callee, Some(&expr.node));
+ for argument in arguments {
+ self.resolve_expr(argument, None);
+ }
+ }
+
_ => {
visit::walk_expr(self, expr);
}
// field, we need to add any trait methods we find that match
// the field name so that we can do some nice error reporting
// later on in typeck.
- let traits = self.get_traits_containing_item(name.node.name);
+ let traits = self.get_traits_containing_item(name.node.name, ValueNS);
self.trait_map.insert(expr.id, traits);
}
ExprKind::MethodCall(name, ..) => {
debug!("(recording candidate traits for expr) recording traits for {}",
expr.id);
- let traits = self.get_traits_containing_item(name.node.name);
+ let traits = self.get_traits_containing_item(name.node.name, ValueNS);
self.trait_map.insert(expr.id, traits);
}
_ => {
}
}
- fn get_traits_containing_item(&mut self, name: Name) -> Vec<TraitCandidate> {
+ fn get_traits_containing_item(&mut self, name: Name, ns: Namespace) -> Vec<TraitCandidate> {
debug!("(getting traits containing item) looking for '{}'", name);
let mut found_traits = Vec::new();
// Look for the current trait.
if let Some((trait_def_id, _)) = self.current_trait_ref {
- if self.trait_item_map.contains_key(&(name, trait_def_id)) {
+ if self.trait_item_map.contains_key(&(trait_def_id, name, ns)) {
found_traits.push(TraitCandidate { def_id: trait_def_id, import_id: None });
}
}
let mut search_module = self.current_module;
loop {
- self.get_traits_in_module_containing_item(name, search_module, &mut found_traits);
+ self.get_traits_in_module_containing_item(name, ns, search_module, &mut found_traits);
match search_module.kind {
ModuleKind::Block(..) => search_module = search_module.parent.unwrap(),
_ => break,
if let Some(prelude) = self.prelude {
if !search_module.no_implicit_prelude {
- self.get_traits_in_module_containing_item(name, prelude, &mut found_traits);
+ self.get_traits_in_module_containing_item(name, ns, prelude, &mut found_traits);
}
}
fn get_traits_in_module_containing_item(&mut self,
name: Name,
+ ns: Namespace,
module: Module,
found_traits: &mut Vec<TraitCandidate>) {
let mut traits = module.traits.borrow_mut();
for &(trait_name, binding) in traits.as_ref().unwrap().iter() {
let trait_def_id = binding.def().def_id();
- if self.trait_item_map.contains_key(&(name, trait_def_id)) {
+ if self.trait_item_map.contains_key(&(trait_def_id, name, ns)) {
let import_id = match binding.kind {
NameBindingKind::Import { directive, .. } => {
self.maybe_unused_trait_imports.insert(directive.id);
///
/// NOTE: The method does not look into imports, but this is not a problem,
/// since we report the definitions (thus, the de-aliased imports).
- fn lookup_candidates<FilterFn>(&mut self,
- lookup_name: Name,
- namespace: Namespace,
- filter_fn: FilterFn) -> SuggestedCandidates
- where FilterFn: Fn(Def) -> bool {
-
- let mut lookup_results = Vec::new();
+ fn lookup_import_candidates<FilterFn>(&mut self,
+ lookup_name: Name,
+ namespace: Namespace,
+ filter_fn: FilterFn)
+ -> Vec<ImportSuggestion>
+ where FilterFn: Fn(Def) -> bool
+ {
+ let mut candidates = Vec::new();
let mut worklist = Vec::new();
+ let mut seen_modules = FxHashSet();
worklist.push((self.graph_root, Vec::new(), false));
while let Some((in_module,
// avoid imports entirely
if name_binding.is_import() && !name_binding.is_extern_crate() { return; }
+ // avoid non-importable candidates as well
+ if !name_binding.is_importable() { return; }
// collect results based on the filter function
if ident.name == lookup_name && ns == namespace {
segms.push(ident.into());
let path = Path {
span: span,
- global: false,
segments: segms,
};
// the entity is accessible in the following cases:
// declared as public (due to pruning, we don't explore
// outside crate private modules => no need to check this)
if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
- lookup_results.push(path);
+ candidates.push(ImportSuggestion { path: path });
}
}
}
if !in_module_is_extern || name_binding.vis == ty::Visibility::Public {
// add the module to the lookup
let is_extern = in_module_is_extern || name_binding.is_extern_crate();
- if !worklist.iter().any(|&(m, ..)| m.def() == module.def()) {
+ if seen_modules.insert(module.def_id().unwrap()) {
worklist.push((module, path_segments, is_extern));
}
}
})
}
- SuggestedCandidates {
- name: lookup_name.as_str().to_string(),
- candidates: lookup_results,
- }
+ candidates
}
fn record_def(&mut self, node_id: NodeId, resolution: PathResolution) {
debug!("(recording def) recording {:?} for {}", resolution, node_id);
+ assert!(resolution.depth == 0 || resolution.base_def != Def::Err);
if let Some(prev_res) = self.def_map.insert(node_id, resolution) {
panic!("path resolved multiple times ({:?} before, {:?} now)", prev_res, resolution);
}
}
fn resolve_visibility(&mut self, vis: &ast::Visibility) -> ty::Visibility {
- let (segments, span, id) = match *vis {
- ast::Visibility::Public => return ty::Visibility::Public,
- ast::Visibility::Crate(_) => return ty::Visibility::Restricted(ast::CRATE_NODE_ID),
- ast::Visibility::Restricted { ref path, id } => (&path.segments, path.span, id),
+ match *vis {
+ ast::Visibility::Public => ty::Visibility::Public,
+ ast::Visibility::Crate(..) => ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX)),
ast::Visibility::Inherited => {
- return ty::Visibility::Restricted(self.current_module.normal_ancestor_id.unwrap());
+ ty::Visibility::Restricted(self.current_module.normal_ancestor_id)
}
- };
-
- let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
- let mut path_resolution = err_path_resolution();
- let vis = match self.resolve_path(&path, PathScope::Import, None, Some(span)) {
- PathResult::Module(module) => {
- path_resolution = PathResolution::new(module.def().unwrap());
- ty::Visibility::Restricted(module.normal_ancestor_id.unwrap())
- }
- PathResult::Failed(msg, _) => {
- self.session.span_err(span, &format!("failed to resolve module path. {}", msg));
- ty::Visibility::Public
+ ast::Visibility::Restricted { ref path, id } => {
+ let def = self.smart_resolve_path(id, None, path, PathSource::Visibility).base_def;
+ if def == Def::Err {
+ ty::Visibility::Public
+ } else {
+ let vis = ty::Visibility::Restricted(def.def_id());
+ if self.is_accessible(vis) {
+ vis
+ } else {
+ self.session.span_err(path.span, "visibilities can only be restricted \
+ to ancestor modules");
+ ty::Visibility::Public
+ }
+ }
}
- _ => ty::Visibility::Public,
- };
- self.def_map.insert(id, path_resolution);
- if !self.is_accessible(vis) {
- let msg = format!("visibilities can only be restricted to ancestor modules");
- self.session.span_err(span, &msg);
}
- vis
}
fn is_accessible(&self, vis: ty::Visibility) -> bool {
- vis.is_accessible_from(self.current_module.normal_ancestor_id.unwrap(), self)
+ vis.is_accessible_from(self.current_module.normal_ancestor_id, self)
}
fn is_accessible_from(&self, vis: ty::Visibility, module: Module<'a>) -> bool {
- vis.is_accessible_from(module.normal_ancestor_id.unwrap(), self)
+ vis.is_accessible_from(module.normal_ancestor_id, self)
}
fn report_errors(&mut self) {
}
}
-fn names_to_string(names: &[Ident]) -> String {
- let mut first = true;
+fn is_struct_like(def: Def) -> bool {
+ match def {
+ Def::VariantCtor(_, CtorKind::Fictive) => true,
+ _ => PathSource::Struct.is_expected(def),
+ }
+}
+
+fn is_self_type(path: &[Ident], namespace: Namespace) -> bool {
+ namespace == TypeNS && path.len() == 1 && path[0].name == keywords::SelfType.name()
+}
+
+fn is_self_value(path: &[Ident], namespace: Namespace) -> bool {
+ namespace == ValueNS && path.len() == 1 && path[0].name == keywords::SelfValue.name()
+}
+
+fn names_to_string(idents: &[Ident]) -> String {
let mut result = String::new();
- for ident in names {
- if first {
- first = false
- } else {
- result.push_str("::")
+ for (i, ident) in idents.iter().filter(|i| i.name != keywords::CrateRoot.name()).enumerate() {
+ if i > 0 {
+ result.push_str("::");
}
result.push_str(&ident.name.as_str());
}
result
}
-fn path_names_to_string(path: &Path, depth: usize) -> String {
- let names: Vec<_> =
- path.segments[..path.segments.len() - depth].iter().map(|seg| seg.identifier).collect();
- names_to_string(&names)
+fn path_names_to_string(path: &Path) -> String {
+ names_to_string(&path.segments.iter().map(|seg| seg.identifier).collect::<Vec<_>>())
}
/// When an entity with a given name is not available in scope, we search for
/// entities with that name in all crates. This method allows outputting the
/// results of this search in a programmer-friendly way
fn show_candidates(session: &mut DiagnosticBuilder,
- candidates: &SuggestedCandidates) {
-
- let paths = &candidates.candidates;
-
- if paths.len() > 0 {
- // don't show more than MAX_CANDIDATES results, so
- // we're consistent with the trait suggestions
- const MAX_CANDIDATES: usize = 5;
-
- // we want consistent results across executions, but candidates are produced
- // by iterating through a hash map, so make sure they are ordered:
- let mut path_strings: Vec<_> = paths.into_iter()
- .map(|p| path_names_to_string(&p, 0))
- .collect();
- path_strings.sort();
-
- // behave differently based on how many candidates we have:
- if !paths.is_empty() {
- if paths.len() == 1 {
- session.help(
- &format!("you can import it into scope: `use {};`.",
- &path_strings[0]),
- );
- } else {
- session.help("you can import several candidates \
- into scope (`use ...;`):");
- let count = path_strings.len() as isize - MAX_CANDIDATES as isize + 1;
-
- for (idx, path_string) in path_strings.iter().enumerate() {
- if idx == MAX_CANDIDATES - 1 && count > 1 {
- session.help(
- &format!(" and {} other candidates", count).to_string(),
- );
- break;
- } else {
- session.help(
- &format!(" `{}`", path_string).to_string(),
- );
- }
- }
- }
- }
- } else {
- // nothing found:
- session.help(
- &format!("no candidates by the name of `{}` found in your \
- project; maybe you misspelled the name or forgot to import \
- an external crate?", candidates.name.to_string()),
- );
+ candidates: &[ImportSuggestion],
+ better: bool) {
+ // don't show more than MAX_CANDIDATES results, so
+ // we're consistent with the trait suggestions
+ const MAX_CANDIDATES: usize = 5;
+
+ // we want consistent results across executions, but candidates are produced
+ // by iterating through a hash map, so make sure they are ordered:
+ let mut path_strings: Vec<_> =
+ candidates.into_iter().map(|c| path_names_to_string(&c.path)).collect();
+ path_strings.sort();
+
+ let better = if better { "better " } else { "" };
+ let msg_diff = match path_strings.len() {
+ 1 => " is found in another module, you can import it",
+ _ => "s are found in other modules, you can import them",
};
+ session.help(&format!("possible {}candidate{} into scope:", better, msg_diff));
+
+ let count = path_strings.len() as isize - MAX_CANDIDATES as isize + 1;
+ for (idx, path_string) in path_strings.iter().enumerate() {
+ if idx == MAX_CANDIDATES - 1 && count > 1 {
+ session.help(
+ &format!(" and {} other candidates", count).to_string(),
+ );
+ break;
+ } else {
+ session.help(
+ &format!(" `use {};`", path_string).to_string(),
+ );
+ }
+ }
}
/// A somewhat inefficient routine to obtain the name of a module.
// except according to those terms.
use {AmbiguityError, Resolver, ResolutionError, resolve_error};
-use {Module, ModuleKind, NameBinding, NameBindingKind, PathScope, PathResult};
+use {Module, ModuleKind, NameBinding, NameBindingKind, PathResult};
use Namespace::{self, MacroNS};
use build_reduced_graph::BuildReducedGraphVisitor;
use resolve_imports::ImportResolver;
use syntax::feature_gate::{emit_feature_err, GateIssue};
use syntax::fold::Folder;
use syntax::ptr::P;
+use syntax::symbol::keywords;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax::visit::Visitor;
use syntax_pos::{Span, DUMMY_SP};
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark {
let mark = Mark::fresh();
- let module = self.module_map[&id];
+ let module = self.module_map[&self.definitions.local_def_id(id)];
self.invocations.insert(mark, self.arenas.alloc_invocation_data(InvocationData {
module: Cell::new(module),
def_index: module.def_id().unwrap().index,
fn fold_path(&mut self, mut path: ast::Path) -> ast::Path {
let ident = path.segments[0].identifier;
if ident.name == "$crate" {
- path.global = true;
+ path.segments[0].identifier.name = keywords::CrateRoot.name();
let module = self.0.resolve_crate_var(ident.ctxt);
- if module.is_local() {
- path.segments.remove(0);
- } else {
- path.segments[0].identifier = match module.kind {
- ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name),
+ if !module.is_local() {
+ path.segments.insert(1, match module.kind {
+ ModuleKind::Def(_, name) => ast::Ident::with_empty_ctxt(name).into(),
_ => unreachable!(),
- };
+ })
}
}
path
EliminateCrateVar(self).fold_item(item).expect_one("")
}
+ fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool {
+ self.whitelisted_legacy_custom_derives.contains(&name)
+ }
+
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion) {
let invocation = self.invocations[&mark];
self.collect_def_ids(invocation, expansion);
let binding = self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Def(Def::Macro(def_id)),
span: DUMMY_SP,
- vis: ty::Visibility::PrivateExternal,
+ vis: ty::Visibility::Invisible,
expansion: Mark::root(),
});
self.builtin_macros.insert(ident.name, binding);
fn resolve_macro(&mut self, scope: Mark, path: &ast::Path, force: bool)
-> Result<Rc<SyntaxExtension>, Determinacy> {
- let ast::Path { ref segments, global, span } = *path;
+ let ast::Path { ref segments, span } = *path;
if segments.iter().any(|segment| segment.parameters.is_some()) {
let kind =
if segments.last().unwrap().parameters.is_some() { "macro" } else { "module" };
return Err(Determinacy::Determined);
}
- let path_scope = if global { PathScope::Global } else { PathScope::Lexical };
let path: Vec<_> = segments.iter().map(|seg| seg.identifier).collect();
let invocation = self.invocations[&scope];
self.current_module = invocation.module.get();
- if path.len() > 1 || global {
+ if path.len() > 1 {
if !self.use_extern_macros {
let msg = "non-ident macro paths are experimental";
let feature = "use_extern_macros";
return Err(Determinacy::Determined);
}
- let ext = match self.resolve_path(&path, path_scope, Some(MacroNS), None) {
+ let ext = match self.resolve_path(&path, Some(MacroNS), None) {
PathResult::NonModule(path_res) => match path_res.base_def {
Def::Err => Err(Determinacy::Determined),
def @ _ => Ok(self.get_macro(def)),
_ => Err(Determinacy::Determined),
};
self.current_module.macro_resolutions.borrow_mut()
- .push((path.into_boxed_slice(), path_scope, span));
+ .push((path.into_boxed_slice(), span));
return ext;
}
pub fn finalize_current_module_macro_resolutions(&mut self) {
let module = self.current_module;
- for &(ref path, scope, span) in module.macro_resolutions.borrow().iter() {
- match self.resolve_path(path, scope, Some(MacroNS), Some(span)) {
+ for &(ref path, span) in module.macro_resolutions.borrow().iter() {
+ match self.resolve_path(path, Some(MacroNS), Some(span)) {
PathResult::NonModule(_) => {},
PathResult::Failed(msg, _) => {
resolve_error(self, span, ResolutionError::FailedToResolve(&msg));
use {AmbiguityError, Module, PerNS};
use Namespace::{self, TypeNS, MacroNS};
-use {NameBinding, NameBindingKind, PathResult, PathScope, PrivacyError};
+use {NameBinding, NameBindingKind, PathResult, PrivacyError};
use Resolver;
use {names_to_string, module_to_string};
use {resolve_error, ResolutionError};
use rustc::ty;
use rustc::lint::builtin::PRIVATE_IN_PUBLIC;
+use rustc::hir::def_id::DefId;
use rustc::hir::def::*;
use syntax::ast::{Ident, NodeId};
use syntax::ext::base::Determinacy::{self, Determined, Undetermined};
use syntax::ext::hygiene::Mark;
+use syntax::parse::token;
use syntax::symbol::keywords;
use syntax::util::lev_distance::find_best_match_for_name;
use syntax_pos::Span;
impl<'a> Resolver<'a> {
fn resolution(&self, module: Module<'a>, ident: Ident, ns: Namespace)
-> &'a RefCell<NameResolution<'a>> {
+ let ident = ident.unhygienize();
*module.resolutions.borrow_mut().entry((ident, ns))
.or_insert_with(|| self.arenas.alloc_name_resolution())
}
ignore_unresolved_invocations: bool,
record_used: Option<Span>)
-> Result<&'a NameBinding<'a>, Determinacy> {
- let ident = ident.unhygienize();
self.populate_module_if_necessary(module);
let resolution = self.resolution(module, ident, ns)
// Given a binding and an import directive that resolves to it,
// return the corresponding binding defined by the import directive.
- pub fn import(&mut self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
+ pub fn import(&self, binding: &'a NameBinding<'a>, directive: &'a ImportDirective<'a>)
-> &'a NameBinding<'a> {
let vis = if binding.pseudo_vis().is_at_least(directive.vis.get(), self) ||
!directive.is_glob() && binding.is_extern_crate() { // c.f. `PRIVATE_IN_PUBLIC`
ns: Namespace,
binding: &'a NameBinding<'a>)
-> Result<(), &'a NameBinding<'a>> {
- let ident = ident.unhygienize();
self.update_resolution(module, ident, ns, |this, resolution| {
if let Some(old_binding) = resolution.binding {
if binding.is_glob_import() {
resolution.shadows_glob = Some(binding);
} else if binding.def() != old_binding.def() {
resolution.binding = Some(this.ambiguity(old_binding, binding));
- } else if !old_binding.vis.is_at_least(binding.vis, this) {
+ } else if !old_binding.vis.is_at_least(binding.vis, &*this) {
// We are glob-importing the same item but with greater visibility.
resolution.binding = Some(binding);
}
})
}
- pub fn ambiguity(&mut self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>)
+ pub fn ambiguity(&self, b1: &'a NameBinding<'a>, b2: &'a NameBinding<'a>)
-> &'a NameBinding<'a> {
self.arenas.alloc_name_binding(NameBinding {
kind: NameBindingKind::Ambiguity { b1: b1, b2: b2, legacy: false },
}
}
-impl<'a, 'b: 'a> ty::NodeIdTree for ImportResolver<'a, 'b> {
- fn is_descendant_of(&self, node: NodeId, ancestor: NodeId) -> bool {
- self.resolver.is_descendant_of(node, ancestor)
+impl<'a, 'b: 'a> ty::DefIdTree for &'a ImportResolver<'a, 'b> {
+ fn parent(self, id: DefId) -> Option<DefId> {
+ self.resolver.parent(id)
}
}
let vis = directive.vis.get();
// For better failure detection, pretend that the import will not define any names
// while resolving its module path.
- directive.vis.set(ty::Visibility::PrivateExternal);
- let result = self.resolve_path(&directive.module_path, PathScope::Import, None, None);
+ directive.vis.set(ty::Visibility::Invisible);
+ let result = self.resolve_path(&directive.module_path, None, None);
directive.vis.set(vis);
match result {
self.current_module = directive.parent;
let ImportDirective { ref module_path, span, .. } = *directive;
- let module_result = self.resolve_path(&module_path, PathScope::Import, None, Some(span));
+ let module_result = self.resolve_path(&module_path, None, Some(span));
let module = match module_result {
PathResult::Module(module) => module,
PathResult::Failed(msg, _) => {
- let mut path = vec![keywords::SelfValue.ident()];
- path.extend(module_path);
- let result = self.resolve_path(&path, PathScope::Import, None, None);
- return if let PathResult::Module(..) = result {
- Some(format!("Did you mean `self::{}`?", &names_to_string(module_path)))
+ let (mut self_path, mut self_result) = (module_path.clone(), None);
+ if !self_path.is_empty() && !token::Ident(self_path[0]).is_path_segment_keyword() {
+ self_path[0].name = keywords::SelfValue.name();
+ self_result = Some(self.resolve_path(&self_path, None, None));
+ }
+ return if let Some(PathResult::Module(..)) = self_result {
+ Some(format!("Did you mean `{}`?", names_to_string(&self_path)))
} else {
Some(msg)
};
}
GlobImport { is_prelude, ref max_vis } => {
if !is_prelude &&
- max_vis.get() != ty::Visibility::PrivateExternal && // Allow empty globs.
- !max_vis.get().is_at_least(directive.vis.get(), self) {
+ max_vis.get() != ty::Visibility::Invisible && // Allow empty globs.
+ !max_vis.get().is_at_least(directive.vis.get(), &*self) {
let msg = "A non-empty glob must import something with the glob's visibility";
self.session.span_err(directive.span, msg);
}
self.per_ns(|this, ns| {
if let Ok(binding) = result[ns].get() {
let vis = directive.vis.get();
- if !binding.pseudo_vis().is_at_least(vis, this) {
+ if !binding.pseudo_vis().is_at_least(vis, &*this) {
reexport_error = Some((ns, binding));
} else {
any_successful_reexport = true;
}
// Record the destination of this import
- self.def_map.insert(directive.id, PathResolution::new(module.def().unwrap()));
+ self.record_def(directive.id, PathResolution::new(module.def().unwrap()));
}
// Miscellaneous post-processing, including recording reexports, reporting conflicts,
match binding.kind {
NameBindingKind::Import { binding: orig_binding, directive, .. } => {
if ns == TypeNS && orig_binding.is_variant() &&
- !orig_binding.vis.is_at_least(binding.vis, self) {
+ !orig_binding.vis.is_at_least(binding.vis, &*self) {
let msg = format!("variant `{}` is private, and cannot be reexported \
(error E0364), consider declaring its enum as `pub`",
ident);
}
fn import_path_to_string(names: &[Ident], subclass: &ImportDirectiveSubclass) -> String {
+ let global = !names.is_empty() && names[0].name == keywords::CrateRoot.name();
+ let names = if global { &names[1..] } else { names };
if names.is_empty() {
import_directive_subclass_to_string(subclass)
} else {
pub variants: Vec<NodeId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
/// Data for extern crates.
pub visibility: Visibility,
pub parent: Option<DefId>,
pub docs: String,
+ pub sig: Signature,
}
/// Data about a function call.
pub parent: Option<DefId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
/// Data for modules.
pub items: Vec<NodeId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
/// Data for a reference to a module.
pub fields: Vec<NodeId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
#[derive(Debug, RustcEncodable)]
pub scope: NodeId,
pub parent: Option<DefId>,
pub docs: String,
+ pub sig: Signature,
}
#[derive(Debug, RustcEncodable)]
pub items: Vec<NodeId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
#[derive(Debug, RustcEncodable)]
pub scope: NodeId,
pub parent: Option<DefId>,
pub docs: String,
+ pub sig: Signature,
}
/// Data for a typedef.
pub visibility: Visibility,
pub parent: Option<DefId>,
pub docs: String,
+ pub sig: Option<Signature>,
}
/// Data for a reference to a type or trait.
pub type_value: String,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Option<Signature>,
}
#[derive(Debug, RustcEncodable)]
pub scope: NodeId,
pub ref_id: DefId,
}
+
+
+/// Encodes information about the signature of a definition. This should have
+/// enough information to create a nice display about a definition without
+/// access to the source code.
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct Signature {
+ pub span: Span,
+ pub text: String,
+ // These identify the main identifier for the defintion as byte offsets into
+ // `text`. E.g., of `foo` in `pub fn foo(...)`
+ pub ident_start: usize,
+ pub ident_end: usize,
+ pub defs: Vec<SigElement>,
+ pub refs: Vec<SigElement>,
+}
+
+/// An element of a signature. `start` and `end` are byte offsets into the `text`
+/// of the parent `Signature`.
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct SigElement {
+ pub id: DefId,
+ pub start: usize,
+ pub end: usize,
+}
// a str representation of the entire prefix.
fn process_path_prefixes(&self, path: &ast::Path) -> Vec<(Span, String)> {
let spans = self.span.spans_for_path_segments(path);
+ let segments = &path.segments[if path.is_global() { 1 } else { 0 }..];
// Paths to enums seem to not match their spans - the span includes all the
// variants too. But they seem to always be at the end, so I hope we can cope with
// always using the first ones. So, only error out if we don't have enough spans.
// What could go wrong...?
- if spans.len() < path.segments.len() {
+ if spans.len() < segments.len() {
if generated_code(path.span) {
return vec![];
}
error!("Mis-calculated spans for path '{}'. Found {} spans, expected {}. Found spans:",
path_to_string(path),
spans.len(),
- path.segments.len());
+ segments.len());
for s in &spans {
let loc = self.sess.codemap().lookup_char_pos(s.lo);
error!(" '{}' in {}, line {}",
let mut result: Vec<(Span, String)> = vec![];
let mut segs = vec![];
- for (i, (seg, span)) in path.segments.iter().zip(&spans).enumerate() {
+ for (i, (seg, span)) in segments.iter().zip(&spans).enumerate() {
segs.push(seg.clone());
let sub_path = ast::Path {
span: *span, // span for the last segment
- global: path.global,
segments: segs,
};
- let qualname = if i == 0 && path.global {
+ let qualname = if i == 0 && path.is_global() {
format!("::{}", path_to_string(&sub_path))
} else {
path_to_string(&sub_path)
result
}
- // The global arg allows us to override the global-ness of the path (which
- // actually means 'does the path start with `::`', rather than 'is the path
- // semantically global). We use the override for `use` imports (etc.) where
- // the syntax is non-global, but the semantics are global.
- fn write_sub_paths(&mut self, path: &ast::Path, global: bool) {
+ fn write_sub_paths(&mut self, path: &ast::Path) {
let sub_paths = self.process_path_prefixes(path);
- for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
- let qualname = if i == 0 && global && !path.global {
- format!("::{}", qualname)
- } else {
- qualname.clone()
- };
+ for (span, qualname) in sub_paths {
self.dumper.mod_ref(ModRefData {
- span: *span,
+ span: span,
qualname: qualname,
scope: self.cur_scope,
ref_id: None
// As write_sub_paths, but does not process the last ident in the path (assuming it
// will be processed elsewhere). See note on write_sub_paths about global.
- fn write_sub_paths_truncated(&mut self, path: &ast::Path, global: bool) {
+ fn write_sub_paths_truncated(&mut self, path: &ast::Path) {
let sub_paths = self.process_path_prefixes(path);
let len = sub_paths.len();
if len <= 1 {
return;
}
- let sub_paths = &sub_paths[..len-1];
- for (i, &(ref span, ref qualname)) in sub_paths.iter().enumerate() {
- let qualname = if i == 0 && global && !path.global {
- format!("::{}", qualname)
- } else {
- qualname.clone()
- };
+ for (span, qualname) in sub_paths.into_iter().take(len - 1) {
self.dumper.mod_ref(ModRefData {
- span: *span,
+ span: span,
qualname: qualname,
scope: self.cur_scope,
ref_id: None
parent: None,
visibility: Visibility::Inherited,
docs: String::new(),
+ sig: None,
}.lower(self.tcx));
}
}
parent: trait_id,
visibility: vis,
docs: docs_for_attrs(attrs),
+ sig: method_data.sig,
}.lower(self.tcx));
}
visibility: Visibility::Inherited,
parent: None,
docs: String::new(),
+ sig: None,
}.lower(self.tcx));
}
}
parent: Some(parent_id),
visibility: vis,
docs: docs_for_attrs(attrs),
+ sig: None,
}.lower(self.tcx));
}
fields: fields,
visibility: From::from(&item.vis),
docs: docs_for_attrs(&item.attrs),
+ sig: self.save_ctxt.sig_base(item),
}.lower(self.tcx));
}
-
- // fields
for field in def.fields() {
self.process_struct_field_def(field, item.id);
self.visit_ty(&field.ty);
qualname.push_str("::");
qualname.push_str(&name);
+ let text = self.span.signature_string_for_span(variant.span);
+ let ident_start = text.find(&name).unwrap();
+ let ident_end = ident_start + name.len();
+ let sig = Signature {
+ span: variant.span,
+ text: text,
+ ident_start: ident_start,
+ ident_end: ident_end,
+ defs: vec![],
+ refs: vec![],
+ };
+
match variant.node.data {
ast::VariantData::Struct(ref fields, _) => {
let sub_span = self.span.span_for_first_ident(variant.span);
scope: enum_data.scope,
parent: Some(make_def_id(item.id, &self.tcx.map)),
docs: docs_for_attrs(&variant.node.attrs),
+ sig: sig,
}.lower(self.tcx));
}
}
scope: enum_data.scope,
parent: Some(make_def_id(item.id, &self.tcx.map)),
docs: docs_for_attrs(&variant.node.attrs),
+ sig: sig,
}.lower(self.tcx));
}
}
items: methods.iter().map(|i| i.id).collect(),
visibility: From::from(&item.vis),
docs: docs_for_attrs(&item.attrs),
+ sig: self.save_ctxt.sig_base(item),
}.lower(self.tcx));
}
Def::Union(..) |
Def::Variant(..) |
Def::TyAlias(..) |
- Def::AssociatedTy(..) => self.write_sub_paths_truncated(path, false),
+ Def::AssociatedTy(..) => self.write_sub_paths_truncated(path),
_ => {}
}
}
fields: &'l [ast::Field],
variant: &'l ty::VariantDef,
base: &'l Option<P<ast::Expr>>) {
- self.write_sub_paths_truncated(path, false);
+ self.write_sub_paths_truncated(path);
if let Some(struct_lit_data) = self.save_ctxt.get_expr_data(ex) {
down_cast_data!(struct_lit_data, TypeRefData, ex.span);
parent: None,
visibility: Visibility::Inherited,
docs: String::new(),
+ sig: None,
}.lower(self.tcx));
}
}
visibility: From::from(&item.vis),
}.lower(self.tcx));
}
- self.write_sub_paths_truncated(path, true);
+ self.write_sub_paths_truncated(path);
}
ast::ViewPathGlob(ref path) => {
// Make a comma-separated list of names of imported modules.
visibility: From::from(&item.vis),
}.lower(self.tcx));
}
- self.write_sub_paths(path, true);
+ self.write_sub_paths(path);
}
ast::ViewPathList(ref path, ref list) => {
for plid in list {
}
}
- self.write_sub_paths(path, true);
+ self.write_sub_paths(path);
}
}
}
Struct(ref def, ref ty_params) => self.process_struct(item, def, ty_params),
Enum(ref def, ref ty_params) => self.process_enum(item, def, ty_params),
Impl(..,
- ref ty_params,
- ref trait_ref,
- ref typ,
- ref impl_items) => {
+ ref ty_params,
+ ref trait_ref,
+ ref typ,
+ ref impl_items) => {
self.process_impl(item, ty_params, trait_ref, &typ, impl_items)
}
Trait(_, ref generics, ref trait_refs, ref methods) =>
visibility: From::from(&item.vis),
parent: None,
docs: docs_for_attrs(&item.attrs),
+ sig: Some(self.save_ctxt.sig_base(item)),
}.lower(self.tcx));
}
}.lower(self.tcx));
}
- self.write_sub_paths_truncated(path, false);
+ self.write_sub_paths_truncated(path);
visit::walk_path(self, path);
}
parent: None,
visibility: Visibility::Inherited,
docs: String::new(),
+ sig: None,
}.lower(self.tcx));
}
}
use syntax::codemap::CodeMap;
use syntax_pos::Span;
-use data::{self, Visibility};
+use data::{self, Visibility, SigElement};
// FIXME: this should be pub(crate), but the current snapshot doesn't allow it yet
pub trait Lower {
pub variants: Vec<DefId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
impl Lower for data::EnumData {
variants: self.variants.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
visibility: self.visibility,
docs: self.docs,
+ sig: self.sig.lower(tcx),
}
}
}
pub visibility: Visibility,
pub parent: Option<DefId>,
pub docs: String,
+ pub sig: Signature,
}
impl Lower for data::FunctionData {
visibility: self.visibility,
parent: self.parent,
docs: self.docs,
+ sig: self.sig.lower(tcx),
}
}
}
pub visibility: Visibility,
pub parent: Option<DefId>,
pub docs: String,
+ pub sig: Signature,
}
impl Lower for data::MethodData {
visibility: self.visibility,
parent: self.parent,
docs: self.docs,
+ sig: self.sig.lower(tcx),
}
}
}
pub items: Vec<DefId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
impl Lower for data::ModData {
items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
visibility: self.visibility,
docs: self.docs,
+ sig: self.sig.lower(tcx),
}
}
}
pub fields: Vec<DefId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
impl Lower for data::StructData {
fields: self.fields.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
visibility: self.visibility,
docs: self.docs,
+ sig: self.sig.lower(tcx),
}
}
}
pub scope: DefId,
pub parent: Option<DefId>,
pub docs: String,
+ pub sig: Signature,
}
impl Lower for data::StructVariantData {
scope: make_def_id(self.scope, &tcx.map),
parent: self.parent,
docs: self.docs,
+ sig: self.sig.lower(tcx),
}
}
}
pub items: Vec<DefId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Signature,
}
impl Lower for data::TraitData {
items: self.items.into_iter().map(|id| make_def_id(id, &tcx.map)).collect(),
visibility: self.visibility,
docs: self.docs,
+ sig: self.sig.lower(tcx),
}
}
}
pub scope: DefId,
pub parent: Option<DefId>,
pub docs: String,
+ pub sig: Signature,
}
impl Lower for data::TupleVariantData {
scope: make_def_id(self.scope, &tcx.map),
parent: self.parent,
docs: self.docs,
+ sig: self.sig.lower(tcx),
}
}
}
pub visibility: Visibility,
pub parent: Option<DefId>,
pub docs: String,
+ pub sig: Option<Signature>,
}
impl Lower for data::TypeDefData {
visibility: self.visibility,
parent: self.parent,
docs: self.docs,
+ sig: self.sig.map(|s| s.lower(tcx)),
}
}
}
pub parent: Option<DefId>,
pub visibility: Visibility,
pub docs: String,
+ pub sig: Option<Signature>,
}
impl Lower for data::VariableData {
parent: self.parent,
visibility: self.visibility,
docs: self.docs,
+ sig: self.sig.map(|s| s.lower(tcx)),
}
}
}
}
}
}
+
+#[derive(Clone, Debug, RustcEncodable)]
+pub struct Signature {
+ pub span: SpanData,
+ pub text: String,
+ // These identify the main identifier for the defintion as byte offsets into
+ // `text`. E.g., of `foo` in `pub fn foo(...)`
+ pub ident_start: usize,
+ pub ident_end: usize,
+ pub defs: Vec<SigElement>,
+ pub refs: Vec<SigElement>,
+}
+
+impl Lower for data::Signature {
+ type Target = Signature;
+
+ fn lower(self, tcx: TyCtxt) -> Signature {
+ Signature {
+ span: SpanData::from_span(self.span, tcx.sess.codemap()),
+ text: self.text,
+ ident_start: self.ident_start,
+ ident_end: self.ident_end,
+ defs: self.defs,
+ refs: self.refs,
+ }
+ }
+}
use rustc_serialize::json::as_json;
use external_data::*;
-use data::{VariableKind, Visibility};
+use data::{VariableKind, Visibility, SigElement};
use dump::Dump;
use super::Format;
children: Vec<Id>,
decl_id: Option<Id>,
docs: String,
+ sig: Option<JsonSignature>,
}
#[derive(Debug, RustcEncodable)]
children: data.variants.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}),
_ => None,
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
})
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
})
}
}
children: data.fields.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}),
_ => None,
}
parent: None,
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}),
_ => None,
}
parent: data.parent.map(|id| From::from(id)),
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}),
_ => None,
}
parent: data.parent.map(|id| From::from(id)),
decl_id: data.decl_id.map(|id| From::from(id)),
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}),
_ => None,
}
parent: None,
decl_id: None,
docs: data.docs,
+ sig: None,
})
}
}
parent: None,
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}),
_ => None,
}
parent: data.parent.map(|id| From::from(id)),
decl_id: None,
docs: String::new(),
+ sig: data.sig.map(|s| From::from(s)),
}),
_ => None,
}
}
}
+
impl From<VariableData> for Option<Def> {
fn from(data: VariableData) -> Option<Def> {
match data.visibility {
parent: data.parent.map(|id| From::from(id)),
decl_id: None,
docs: data.docs,
+ sig: data.sig.map(|s| From::from(s)),
}),
_ => None,
}
}
}
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSignature {
+ span: SpanData,
+ text: String,
+ ident_start: usize,
+ ident_end: usize,
+ defs: Vec<JsonSigElement>,
+ refs: Vec<JsonSigElement>,
+}
+
+impl From<Signature> for JsonSignature {
+ fn from(data: Signature) -> JsonSignature {
+ JsonSignature {
+ span: data.span,
+ text: data.text,
+ ident_start: data.ident_start,
+ ident_end: data.ident_end,
+ defs: data.defs.into_iter().map(|s| From::from(s)).collect(),
+ refs: data.refs.into_iter().map(|s| From::from(s)).collect(),
+ }
+ }
+}
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSigElement {
+ id: Id,
+ start: usize,
+ end: usize,
+}
+
+impl From<SigElement> for JsonSigElement {
+ fn from(data: SigElement) -> JsonSigElement {
+ JsonSigElement {
+ id: From::from(data.id),
+ start: data.start,
+ end: data.end,
+ }
+ }
+}
use rustc_serialize::json::as_json;
use external_data::*;
-use data::VariableKind;
+use data::{VariableKind, SigElement};
use dump::Dump;
use super::Format;
children: data.items.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
};
if def.span.file_name != def.value {
// If the module is an out-of-line defintion, then we'll make the
children: Vec<Id>,
decl_id: Option<Id>,
docs: String,
+ sig: Option<JsonSignature>,
}
#[derive(Debug, RustcEncodable)]
children: data.variants.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}
}
}
children: data.fields.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}
}
}
children: data.items.into_iter().map(|id| From::from(id)).collect(),
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}
}
}
children: vec![],
decl_id: data.decl_id.map(|id| From::from(id)),
docs: data.docs,
+ sig: Some(From::from(data.sig)),
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: None,
}
}
}
-
impl From<TypeDefData> for Def {
fn from(data: TypeDefData) -> Def {
Def {
children: vec![],
decl_id: None,
docs: String::new(),
+ sig: data.sig.map(|s| From::from(s)),
}
}
}
children: vec![],
decl_id: None,
docs: data.docs,
+ sig: None,
}
}
}
}
}
}
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSignature {
+ span: SpanData,
+ text: String,
+ ident_start: usize,
+ ident_end: usize,
+ defs: Vec<JsonSigElement>,
+ refs: Vec<JsonSigElement>,
+}
+
+impl From<Signature> for JsonSignature {
+ fn from(data: Signature) -> JsonSignature {
+ JsonSignature {
+ span: data.span,
+ text: data.text,
+ ident_start: data.ident_start,
+ ident_end: data.ident_end,
+ defs: data.defs.into_iter().map(|s| From::from(s)).collect(),
+ refs: data.refs.into_iter().map(|s| From::from(s)).collect(),
+ }
+ }
+}
+
+#[derive(Debug, RustcEncodable)]
+pub struct JsonSigElement {
+ id: Id,
+ start: usize,
+ end: usize,
+}
+
+impl From<SigElement> for JsonSigElement {
+ fn from(data: SigElement) -> JsonSigElement {
+ JsonSigElement {
+ id: From::from(data.id),
+ start: data.start,
+ end: data.end,
+ }
+ }
+}
visibility: From::from(&item.vis),
parent: None,
docs: docs_for_attrs(&item.attrs),
+ sig: self.sig_base(item),
}))
}
ast::ItemKind::Static(ref typ, mt, ref expr) => {
type_value: ty_to_string(&typ),
visibility: From::from(&item.vis),
docs: docs_for_attrs(&item.attrs),
+ sig: Some(self.sig_base(item)),
}))
}
ast::ItemKind::Const(ref typ, ref expr) => {
type_value: ty_to_string(&typ),
visibility: From::from(&item.vis),
docs: docs_for_attrs(&item.attrs),
+ sig: Some(self.sig_base(item)),
}))
}
ast::ItemKind::Mod(ref m) => {
let sub_span = self.span_utils.sub_span_after_keyword(item.span, keywords::Mod);
filter!(self.span_utils, sub_span, item.span, None);
+
Some(Data::ModData(ModData {
id: item.id,
name: item.ident.to_string(),
items: m.items.iter().map(|i| i.id).collect(),
visibility: From::from(&item.vis),
docs: docs_for_attrs(&item.attrs),
+ sig: self.sig_base(item),
}))
}
ast::ItemKind::Enum(ref def, _) => {
variants: def.variants.iter().map(|v| v.node.data.id()).collect(),
visibility: From::from(&item.vis),
docs: docs_for_attrs(&item.attrs),
+ sig: self.sig_base(item),
}))
}
ast::ItemKind::Impl(.., ref trait_ref, ref typ, _) => {
}
}
- pub fn get_field_data(&self, field: &ast::StructField,
- scope: NodeId) -> Option<VariableData> {
+ pub fn get_field_data(&self,
+ field: &ast::StructField,
+ scope: NodeId)
+ -> Option<VariableData> {
if let Some(ident) = field.ident {
+ let name = ident.to_string();
let qualname = format!("::{}::{}", self.tcx.node_path_str(scope), ident);
- let def_id = self.tcx.map.local_def_id(field.id);
- let typ = self.tcx.item_type(def_id).to_string();
let sub_span = self.span_utils.sub_span_before_token(field.span, token::Colon);
filter!(self.span_utils, sub_span, field.span, None);
+ let def_id = self.tcx.map.local_def_id(field.id);
+ let typ = self.tcx.item_type(def_id).to_string();
+
+ let span = field.span;
+ let text = self.span_utils.snippet(field.span);
+ let ident_start = text.find(&name).unwrap();
+ let ident_end = ident_start + name.len();
+ let sig = Signature {
+ span: span,
+ text: text,
+ ident_start: ident_start,
+ ident_end: ident_end,
+ defs: vec![],
+ refs: vec![],
+ };
Some(VariableData {
id: field.id,
kind: VariableKind::Field,
- name: ident.to_string(),
+ name: name,
qualname: qualname,
span: sub_span.unwrap(),
scope: scope,
type_value: typ,
visibility: From::from(&field.vis),
docs: docs_for_attrs(&field.attrs),
+ sig: Some(sig),
})
} else {
None
match item.node {
hir::ItemImpl(.., ref ty, _) => {
let mut result = String::from("<");
- result.push_str(&rustc::hir::print::ty_to_string(&ty));
+ result.push_str(&self.tcx.map.node_to_pretty_string(ty.id));
let trait_id = self.tcx.trait_id_of_impl(impl_id);
let mut decl_id = None;
let sub_span = self.span_utils.sub_span_after_keyword(span, keywords::Fn);
filter!(self.span_utils, sub_span, span, None);
+
+ let name = name.to_string();
+ let text = self.span_utils.signature_string_for_span(span);
+ let ident_start = text.find(&name).unwrap();
+ let ident_end = ident_start + name.len();
+ let sig = Signature {
+ span: span,
+ text: text,
+ ident_start: ident_start,
+ ident_end: ident_end,
+ defs: vec![],
+ refs: vec![],
+ };
+
Some(FunctionData {
id: id,
- name: name.to_string(),
+ name: name,
qualname: qualname,
declaration: decl_id,
span: sub_span.unwrap(),
visibility: vis,
parent: parent_scope,
docs: docs,
+ sig: sig,
})
}
}
}
+ fn sig_base(&self, item: &ast::Item) -> Signature {
+ let text = self.span_utils.signature_string_for_span(item.span);
+ let name = item.ident.to_string();
+ let ident_start = text.find(&name).expect("Name not in signature?");
+ let ident_end = ident_start + name.len();
+ Signature {
+ span: mk_sp(item.span.lo, item.span.lo + BytePos(text.len() as u32)),
+ text: text,
+ ident_start: ident_start,
+ ident_end: ident_end,
+ defs: vec![],
+ refs: vec![],
+ }
+ }
+
#[inline]
pub fn enclosing_scope(&self, id: NodeId) -> NodeId {
self.tcx.map.get_enclosing_scope(id).unwrap_or(CRATE_NODE_ID)
use syntax::ast;
use syntax::parse::lexer::{self, Reader, StringReader};
use syntax::parse::token::{self, Token};
+use syntax::parse::parser::Parser;
use syntax::symbol::keywords;
+use syntax::tokenstream::TokenTree;
use syntax_pos::*;
#[derive(Clone)]
lexer::StringReader::new(s.diagnostic(), filemap)
}
+ fn span_to_tts(&self, span: Span) -> Vec<TokenTree> {
+ let srdr = self.retokenise_span(span);
+ let mut p = Parser::new(&self.sess.parse_sess, Box::new(srdr), None, false);
+ p.parse_all_token_trees().expect("Couldn't re-parse span")
+ }
+
// Re-parses a path and returns the span for the last identifier in the path
pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
let mut result = None;
}
}
+ /// `span` must be the span for an item such as a function or struct. This
+ /// function returns the program text from the start of the span until the
+ /// 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 prev = toks.next().unwrap();
+ let first_span = prev.get_span();
+ let mut angle_count = 0;
+ for tok in toks {
+ if let TokenTree::Token(_, ref tok) = prev {
+ angle_count += match *tok {
+ token::Eof => { break; }
+ token::Lt => 1,
+ token::Gt => -1,
+ token::BinOp(token::Shl) => 2,
+ token::BinOp(token::Shr) => -2,
+ _ => 0,
+ };
+ }
+ if angle_count > 0 {
+ prev = tok;
+ continue;
+ }
+ if let TokenTree::Token(_, token::Semi) = tok {
+ return self.snippet(mk_sp(first_span.lo, prev.get_span().hi));
+ } else if let TokenTree::Delimited(_, ref d) = tok {
+ if d.delim == token::Brace {
+ return self.snippet(mk_sp(first_span.lo, prev.get_span().hi));
+ }
+ }
+ prev = tok;
+ }
+ self.snippet(span)
+ }
+
pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
let mut toks = self.retokenise_span(span);
let mut prev = toks.real_token();
--- /dev/null
+See [librustc/README.md](../librustc/README.md).
+++ /dev/null
-See the README.md in ../librustc.
use cabi_mips64;
use cabi_asmjs;
use cabi_msp430;
+use cabi_sparc;
+use cabi_nvptx;
+use cabi_nvptx64;
use machine::{llalign_of_min, llsize_of, llsize_of_alloc};
use type_::Type;
use type_of;
// The subset of llvm::Attribute needed for arguments, packed into a bitfield.
bitflags! {
#[derive(Default, Debug)]
- flags ArgAttribute : u8 {
+ flags ArgAttribute : u16 {
const ByVal = 1 << 0,
const NoAlias = 1 << 1,
const NoCapture = 1 << 2,
const SExt = 1 << 5,
const StructRet = 1 << 6,
const ZExt = 1 << 7,
+ const InReg = 1 << 8,
}
}
}
impl ArgAttribute {
fn for_each_kind<F>(&self, mut f: F) where F: FnMut(llvm::Attribute) {
for_each_kind!(self, f,
- ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt)
+ ByVal, NoAlias, NoCapture, NonNull, ReadOnly, SExt, StructRet, ZExt, InReg)
}
}
Win64 => llvm::X86_64_Win64,
SysV64 => llvm::X86_64_SysV,
Aapcs => llvm::ArmAapcsCallConv,
+ PtxKernel => llvm::PtxKernel,
// These API constants ought to be more specific...
Cdecl => llvm::CCallConv,
}
match &ccx.sess().target.target.arch[..] {
- "x86" => cabi_x86::compute_abi_info(ccx, self),
+ "x86" => {
+ let flavor = if abi == Abi::Fastcall {
+ cabi_x86::Flavor::Fastcall
+ } else {
+ cabi_x86::Flavor::General
+ };
+ cabi_x86::compute_abi_info(ccx, self, flavor);
+ },
"x86_64" => if abi == Abi::SysV64 {
cabi_x86_64::compute_abi_info(ccx, self);
} else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows {
"asmjs" => cabi_asmjs::compute_abi_info(ccx, self),
"wasm32" => cabi_asmjs::compute_abi_info(ccx, self),
"msp430" => cabi_msp430::compute_abi_info(ccx, self),
+ "sparc" => cabi_sparc::compute_abi_info(ccx, self),
+ "nvptx" => cabi_nvptx::compute_abi_info(ccx, self),
+ "nvptx64" => cabi_nvptx64::compute_abi_info(ccx, self),
a => ccx.sess().fatal(&format!("unrecognized arch \"{}\" in target specification", a))
}
let mut out_filenames = Vec::new();
for &crate_type in sess.crate_types.borrow().iter() {
// Ignore executable crates if we have -Z no-trans, as they will error.
- if sess.opts.debugging_opts.no_trans &&
+ if (sess.opts.debugging_opts.no_trans ||
+ !sess.opts.output_types.should_trans()) &&
crate_type == config::CrateTypeExecutable {
continue;
}
bug!("invalid output type `{:?}` for target os `{}`",
crate_type, sess.opts.target_triple);
}
- let out_file = link_binary_output(sess, trans, crate_type, outputs,
- crate_name);
- out_filenames.push(out_file);
+ let mut out_files = link_binary_output(sess, trans, crate_type, outputs, crate_name);
+ out_filenames.append(&mut out_files);
}
// Remove the temporary object file and metadata if we aren't saving temps
if !sess.opts.cg.save_temps {
- for obj in object_filenames(trans, outputs) {
- remove(sess, &obj);
+ if sess.opts.output_types.should_trans() {
+ for obj in object_filenames(trans, outputs) {
+ remove(sess, &obj);
+ }
}
remove(sess, &outputs.with_extension("metadata.o"));
}
}
}
+fn filename_for_metadata(sess: &Session, crate_name: &str, outputs: &OutputFilenames) -> PathBuf {
+ let out_filename = outputs.single_output_file.clone()
+ .unwrap_or(outputs
+ .out_directory
+ .join(&format!("lib{}{}.rmeta", crate_name, sess.opts.cg.extra_filename)));
+ check_file_is_writeable(&out_filename, sess);
+ out_filename
+}
+
pub fn filename_for_input(sess: &Session,
crate_type: config::CrateType,
crate_name: &str,
outputs: &OutputFilenames) -> PathBuf {
let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename);
+
match crate_type {
config::CrateTypeRlib => {
outputs.out_directory.join(&format!("lib{}.rlib", libname))
}
- config::CrateTypeMetadata => {
- outputs.out_directory.join(&format!("lib{}.rmeta", libname))
- }
config::CrateTypeCdylib |
config::CrateTypeProcMacro |
config::CrateTypeDylib => {
}
}
+fn out_filename(sess: &Session,
+ crate_type: config::CrateType,
+ outputs: &OutputFilenames,
+ crate_name: &str)
+ -> PathBuf {
+ let default_filename = filename_for_input(sess, crate_type, crate_name, outputs);
+ let out_filename = outputs.outputs.get(&OutputType::Exe)
+ .and_then(|s| s.to_owned())
+ .or_else(|| outputs.single_output_file.clone())
+ .unwrap_or(default_filename);
+
+ check_file_is_writeable(&out_filename, sess);
+
+ out_filename
+}
+
+// Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
+// check this already -- however, the Linux linker will happily overwrite a
+// read-only file. We should be consistent.
+fn check_file_is_writeable(file: &Path, sess: &Session) {
+ if !is_writeable(file) {
+ sess.fatal(&format!("output file {} is not writeable -- check its \
+ permissions", file.display()));
+ }
+}
+
fn link_binary_output(sess: &Session,
trans: &CrateTranslation,
crate_type: config::CrateType,
outputs: &OutputFilenames,
- crate_name: &str) -> PathBuf {
+ crate_name: &str) -> Vec<PathBuf> {
let objects = object_filenames(trans, outputs);
- let default_filename = filename_for_input(sess, crate_type, crate_name,
- outputs);
- let out_filename = outputs.outputs.get(&OutputType::Exe)
- .and_then(|s| s.to_owned())
- .or_else(|| outputs.single_output_file.clone())
- .unwrap_or(default_filename);
- // Make sure files are writeable. Mac, FreeBSD, and Windows system linkers
- // check this already -- however, the Linux linker will happily overwrite a
- // read-only file. We should be consistent.
- for file in objects.iter().chain(Some(&out_filename)) {
- if !is_writeable(file) {
- sess.fatal(&format!("output file {} is not writeable -- check its \
- permissions", file.display()));
- }
+ for file in &objects {
+ check_file_is_writeable(file, sess);
}
let tmpdir = match TempDir::new("rustc") {
Err(err) => sess.fatal(&format!("couldn't create a temp dir: {}", err)),
};
- match crate_type {
- config::CrateTypeRlib => {
- link_rlib(sess, Some(trans), &objects, &out_filename,
- tmpdir.path()).build();
- }
- config::CrateTypeStaticlib => {
- link_staticlib(sess, &objects, &out_filename, tmpdir.path());
- }
- config::CrateTypeMetadata => {
- emit_metadata(sess, trans, &out_filename);
- }
- _ => {
- link_natively(sess, crate_type, &objects, &out_filename, trans,
- outputs, tmpdir.path());
+ let mut out_filenames = vec![];
+
+ if outputs.outputs.contains_key(&OutputType::Metadata) {
+ let out_filename = filename_for_metadata(sess, crate_name, outputs);
+ emit_metadata(sess, trans, &out_filename);
+ out_filenames.push(out_filename);
+ }
+
+ if outputs.outputs.should_trans() {
+ let out_filename = out_filename(sess, crate_type, outputs, crate_name);
+ match crate_type {
+ config::CrateTypeRlib => {
+ link_rlib(sess, Some(trans), &objects, &out_filename,
+ tmpdir.path()).build();
+ }
+ config::CrateTypeStaticlib => {
+ link_staticlib(sess, &objects, &out_filename, tmpdir.path());
+ }
+ _ => {
+ link_natively(sess, crate_type, &objects, &out_filename, trans,
+ outputs, tmpdir.path());
+ }
}
+ out_filenames.push(out_filename);
}
- out_filename
+ out_filenames
}
fn object_filenames(trans: &CrateTranslation,
config::CrateTypeDylib |
config::CrateTypeRlib |
- config::CrateTypeMetadata |
config::CrateTypeProcMacro => false,
}
}
config::CrateTypeProcMacro |
config::CrateTypeCdylib => SymbolExportLevel::C,
config::CrateTypeRlib |
- config::CrateTypeMetadata |
config::CrateTypeDylib => SymbolExportLevel::Rust,
}
}
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef, ContextRef};
use llvm::SMDiagnosticRef;
use {CrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation};
-use util::common::time;
+use util::common::{time, time_depth, set_time_depth};
use util::common::path2cstr;
use util::fs::link_or_copy;
use errors::{self, Handler, Level, DiagnosticBuilder};
for output_type in output_types.keys() {
match *output_type {
- OutputType::Bitcode => { modules_config.emit_bc = true; },
- OutputType::LlvmAssembly => { modules_config.emit_ir = true; },
+ OutputType::Bitcode => { modules_config.emit_bc = true; }
+ OutputType::LlvmAssembly => { modules_config.emit_ir = true; }
OutputType::Assembly => {
modules_config.emit_asm = true;
// If we're not using the LLVM assembler, this function
if !sess.opts.output_types.contains_key(&OutputType::Assembly) {
metadata_config.emit_obj = true;
}
- },
- OutputType::Object => { modules_config.emit_obj = true; },
+ }
+ OutputType::Object => { modules_config.emit_obj = true; }
+ OutputType::Metadata => { metadata_config.emit_obj = true; }
OutputType::Exe => {
modules_config.emit_obj = true;
metadata_config.emit_obj = true;
user_wants_objects = true;
copy_if_one_unit(OutputType::Object, true);
}
+ OutputType::Metadata |
OutputType::Exe |
OutputType::DepInfo => {}
}
let incr_comp_session_dir = sess.incr_comp_session_dir_opt().map(|r| r.clone());
+ let depth = time_depth();
thread::Builder::new().name(format!("codegen-{}", i)).spawn(move || {
+ set_time_depth(depth);
+
let diag_handler = Handler::with_emitter(true, false, box diag_emitter);
// Must construct cgcx inside the proc because it has non-Send
config::CrateTypeStaticlib |
config::CrateTypeCdylib => MetadataKind::None,
- config::CrateTypeRlib |
- config::CrateTypeMetadata => MetadataKind::Uncompressed,
+ config::CrateTypeRlib => MetadataKind::Uncompressed,
config::CrateTypeDylib |
config::CrateTypeProcMacro => MetadataKind::Compressed,
// Skip crate items and just output metadata in -Z no-trans mode.
if tcx.sess.opts.debugging_opts.no_trans ||
- tcx.sess.crate_types.borrow().iter().all(|ct| ct == &config::CrateTypeMetadata) {
+ tcx.sess.opts.output_types.contains_key(&config::OutputType::Metadata) {
let linker_info = LinkerInfo::new(&shared_ccx, &ExportedSymbols::empty());
return CrateTranslation {
modules: modules,
--- /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.
+
+// Reference: PTX Writer's Guide to Interoperability
+// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
+
+#![allow(non_upper_case_globals)]
+
+use llvm::Struct;
+
+use abi::{self, ArgType, FnType};
+use context::CrateContext;
+use type_::Type;
+
+fn ty_size(ty: Type) -> usize {
+ abi::ty_size(ty, 4)
+}
+
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+ if ret.ty.kind() == Struct && ty_size(ret.ty) > 32 {
+ ret.make_indirect(ccx);
+ } else {
+ ret.extend_integer_width_to(32);
+ }
+}
+
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
+ if arg.ty.kind() == Struct && ty_size(arg.ty) > 32 {
+ arg.make_indirect(ccx);
+ } else {
+ arg.extend_integer_width_to(32);
+ }
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+ if !fty.ret.is_ignore() {
+ classify_ret_ty(ccx, &mut fty.ret);
+ }
+
+ for arg in &mut fty.args {
+ if arg.is_ignore() {
+ continue;
+ }
+ classify_arg_ty(ccx, arg);
+ }
+}
--- /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.
+
+// Reference: PTX Writer's Guide to Interoperability
+// http://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability
+
+#![allow(non_upper_case_globals)]
+
+use llvm::Struct;
+
+use abi::{self, ArgType, FnType};
+use context::CrateContext;
+use type_::Type;
+
+fn ty_size(ty: Type) -> usize {
+ abi::ty_size(ty, 8)
+}
+
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+ if ret.ty.kind() == Struct && ty_size(ret.ty) > 64 {
+ ret.make_indirect(ccx);
+ } else {
+ ret.extend_integer_width_to(64);
+ }
+}
+
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType) {
+ if arg.ty.kind() == Struct && ty_size(arg.ty) > 64 {
+ arg.make_indirect(ccx);
+ } else {
+ arg.extend_integer_width_to(64);
+ }
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+ if !fty.ret.is_ignore() {
+ classify_ret_ty(ccx, &mut fty.ret);
+ }
+
+ for arg in &mut fty.args {
+ if arg.is_ignore() {
+ continue;
+ }
+ classify_arg_ty(ccx, arg);
+ }
+}
--- /dev/null
+// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![allow(non_upper_case_globals)]
+
+use libc::c_uint;
+use std::cmp;
+use llvm;
+use llvm::{Integer, Pointer, Float, Double, Vector};
+use abi::{self, align_up_to, ArgType, FnType};
+use context::CrateContext;
+use type_::Type;
+
+fn ty_align(ty: Type) -> usize {
+ abi::ty_align(ty, 4)
+}
+
+fn ty_size(ty: Type) -> usize {
+ abi::ty_size(ty, 4)
+}
+
+fn classify_ret_ty(ccx: &CrateContext, ret: &mut ArgType) {
+ if is_reg_ty(ret.ty) {
+ ret.extend_integer_width_to(32);
+ } else {
+ ret.make_indirect(ccx);
+ }
+}
+
+fn classify_arg_ty(ccx: &CrateContext, arg: &mut ArgType, offset: &mut usize) {
+ let orig_offset = *offset;
+ let size = ty_size(arg.ty) * 8;
+ let mut align = ty_align(arg.ty);
+
+ align = cmp::min(cmp::max(align, 4), 8);
+ *offset = align_up_to(*offset, align);
+ *offset += align_up_to(size, align * 8) / 8;
+
+ if !is_reg_ty(arg.ty) {
+ arg.cast = Some(struct_ty(ccx, arg.ty));
+ arg.pad = padding_ty(ccx, align, orig_offset);
+ } else {
+ arg.extend_integer_width_to(32);
+ }
+}
+
+fn is_reg_ty(ty: Type) -> bool {
+ return match ty.kind() {
+ Integer
+ | Pointer
+ | Float
+ | Double
+ | Vector => true,
+ _ => false
+ };
+}
+
+fn padding_ty(ccx: &CrateContext, align: usize, offset: usize) -> Option<Type> {
+ if ((align - 1 ) & offset) > 0 {
+ Some(Type::i32(ccx))
+ } else {
+ None
+ }
+}
+
+fn coerce_to_int(ccx: &CrateContext, size: usize) -> Vec<Type> {
+ let int_ty = Type::i32(ccx);
+ let mut args = Vec::new();
+
+ let mut n = size / 32;
+ while n > 0 {
+ args.push(int_ty);
+ n -= 1;
+ }
+
+ let r = size % 32;
+ if r > 0 {
+ unsafe {
+ args.push(Type::from_ref(llvm::LLVMIntTypeInContext(ccx.llcx(), r as c_uint)));
+ }
+ }
+
+ args
+}
+
+fn struct_ty(ccx: &CrateContext, ty: Type) -> Type {
+ let size = ty_size(ty) * 8;
+ Type::struct_(ccx, &coerce_to_int(ccx, size), false)
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+ if !fty.ret.is_ignore() {
+ classify_ret_ty(ccx, &mut fty.ret);
+ }
+
+ let mut offset = if fty.ret.is_indirect() { 4 } else { 0 };
+ for arg in &mut fty.args {
+ if arg.is_ignore() { continue; }
+ classify_arg_ty(ccx, arg, &mut offset);
+ }
+}
use super::common::*;
use super::machine::*;
-pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType) {
+#[derive(PartialEq)]
+pub enum Flavor {
+ General,
+ Fastcall
+}
+
+pub fn compute_abi_info(ccx: &CrateContext, fty: &mut FnType, flavor: Flavor) {
if !fty.ret.is_ignore() {
if fty.ret.ty.kind() == Struct {
// Returning a structure. Most often, this will use
arg.extend_integer_width_to(32);
}
}
+
+ if flavor == Flavor::Fastcall {
+ // Mark arguments as InReg like clang does it,
+ // so our fastcall is compatible with C/C++ fastcall.
+
+ // Clang reference: lib/CodeGen/TargetInfo.cpp
+ // See X86_32ABIInfo::shouldPrimitiveUseInReg(), X86_32ABIInfo::updateFreeRegs()
+
+ // IsSoftFloatABI is only set to true on ARM platforms,
+ // which in turn can't be x86?
+
+ let mut free_regs = 2;
+
+ for arg in &mut fty.args {
+ if arg.is_ignore() || arg.is_indirect() { continue; }
+
+ if arg.ty.kind() == Float {
+ continue;
+ }
+
+ let size = llbitsize_of_real(ccx, arg.ty);
+ let size_in_regs = (size + 31) / 32;
+
+ if size_in_regs == 0 {
+ continue;
+ }
+
+ if size_in_regs > free_regs {
+ break;
+ }
+
+ free_regs -= size_in_regs;
+
+ if size <= 32 && (arg.ty.kind() == Pointer || arg.ty.kind() == Integer) {
+ arg.attrs.set(ArgAttribute::InReg);
+ }
+
+ if free_regs == 0 {
+ break;
+ }
+ }
+ }
}
use common::{
self, CrateContext, FunctionContext, SharedCrateContext
};
+use adt::MaybeSizedValue;
use consts;
use declare;
use value::Value;
// Call the by-ref closure body with `self` in a cleanup scope,
// to drop `self` when the body returns, or in case it unwinds.
- let self_scope = fcx.schedule_drop_mem(llenv, closure_ty);
+ let self_scope = fcx.schedule_drop_mem(MaybeSizedValue::sized(llenv), closure_ty);
let llfn = callee.reify(bcx.ccx);
let llret;
//! corresponds to a normal exit from a block (for example, an expression
//! completing evaluation successfully without panic).
-use llvm::{BasicBlockRef, ValueRef};
+use llvm::BasicBlockRef;
use base;
+use adt::MaybeSizedValue;
use common::{BlockAndBuilder, FunctionContext, Funclet};
use glue;
use type_::Type;
-use value::Value;
use rustc::ty::Ty;
pub struct CleanupScope<'tcx> {
#[derive(Copy, Clone)]
pub struct DropValue<'tcx> {
- val: ValueRef,
+ val: MaybeSizedValue,
ty: Ty<'tcx>,
skip_dtor: bool,
}
impl<'a, 'tcx> FunctionContext<'a, 'tcx> {
/// Schedules a (deep) drop of `val`, which is a pointer to an instance of `ty`
- pub fn schedule_drop_mem(&self, val: ValueRef, ty: Ty<'tcx>) -> CleanupScope<'tcx> {
+ pub fn schedule_drop_mem(&self, val: MaybeSizedValue, ty: Ty<'tcx>) -> CleanupScope<'tcx> {
if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }
let drop = DropValue {
val: val,
skip_dtor: false,
};
- debug!("schedule_drop_mem(val={:?}, ty={:?}) skip_dtor={}", Value(val), ty, drop.skip_dtor);
-
CleanupScope::new(self, drop)
}
/// `ty`. The scheduled code handles extracting the discriminant
/// and dropping the contents associated with that variant
/// *without* executing any associated drop implementation.
- pub fn schedule_drop_adt_contents(&self, val: ValueRef, ty: Ty<'tcx>) -> CleanupScope<'tcx> {
+ pub fn schedule_drop_adt_contents(&self, val: MaybeSizedValue, ty: Ty<'tcx>)
+ -> CleanupScope<'tcx> {
// `if` below could be "!contents_needs_drop"; skipping drop
// is just an optimization, so sound to be conservative.
if !self.ccx.shared().type_needs_drop(ty) { return CleanupScope::noop(); }
skip_dtor: true,
};
- debug!("schedule_drop_adt_contents(val={:?}, ty={:?}) skip_dtor={}",
- Value(val), ty, drop.skip_dtor);
-
CleanupScope::new(self, drop)
}
}
use rustc::hir::map as hir_map;
use rustc::hir::def_id::DefId;
-use rustc::middle::lang_items::{ExchangeFreeFnLangItem, ExchangeMallocFnLangItem};
+use rustc::middle::lang_items::{BoxFreeFnLangItem, ExchangeMallocFnLangItem};
use rustc::traits;
-use rustc::ty::subst::{Substs, Subst};
+use rustc::ty::subst::{Kind, Substs, Subst};
use rustc::ty::{self, TypeFoldable, TyCtxt};
use rustc::ty::adjustment::CustomCoerceUnsized;
use rustc::mir::{self, Location};
use rustc::mir::visit as mir_visit;
use rustc::mir::visit::Visitor as MirVisitor;
-use rustc_const_eval as const_eval;
-
use syntax::abi::Abi;
use syntax_pos::DUMMY_SP;
use base::custom_coerce_unsize_info;
use trans_item::{TransItem, DefPathBasedNames};
+use std::iter;
+
#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)]
pub enum TransItemCollectionMode {
Eager,
recursion_depth_reset = None;
- // Scan the MIR in order to find function calls, closures, and
- // drop-glue
- let mir = scx.tcx().item_mir(def_id);
-
- let empty_substs = scx.empty_substs_for_def_id(def_id);
- let visitor = MirNeighborCollector {
- scx: scx,
- mir: &mir,
- output: &mut neighbors,
- param_substs: empty_substs
- };
-
- visit_mir_and_promoted(visitor, &mir);
+ collect_neighbours(scx, Instance::mono(scx, def_id), &mut neighbors);
}
TransItem::Fn(instance) => {
// Keep track of the monomorphization recursion depth
recursion_depths));
check_type_length_limit(scx.tcx(), instance);
- // Scan the MIR in order to find function calls, closures, and
- // drop-glue
- let mir = scx.tcx().item_mir(instance.def);
-
- let visitor = MirNeighborCollector {
- scx: scx,
- mir: &mir,
- output: &mut neighbors,
- param_substs: instance.substs
- };
-
- visit_mir_and_promoted(visitor, &mir);
+ collect_neighbours(scx, instance, &mut neighbors);
}
}
// This is not a callee, but we still have to look for
// references to `const` items
if let mir::Literal::Item { def_id, substs } = constant.literal {
- let tcx = self.scx.tcx();
let substs = monomorphize::apply_param_substs(self.scx,
self.param_substs,
&substs);
- // If the constant referred to here is an associated
- // item of a trait, we need to resolve it to the actual
- // constant in the corresponding impl. Luckily
- // const_eval::lookup_const_by_id() does that for us.
- if let Some((expr, _)) = const_eval::lookup_const_by_id(tcx,
- def_id,
- Some(substs)) {
- // The hir::Expr we get here is the initializer of
- // the constant, what we really want is the item
- // DefId.
- let const_node_id = tcx.map.get_parent(expr.id);
- let def_id = if tcx.map.is_inlined_node_id(const_node_id) {
- tcx.sess.cstore.defid_for_inlined_node(const_node_id).unwrap()
- } else {
- tcx.map.local_def_id(const_node_id)
- };
-
- collect_const_item_neighbours(self.scx,
- def_id,
- substs,
- self.output);
- }
+ let instance = Instance::new(def_id, substs).resolve_const(self.scx);
+ collect_neighbours(self.scx, instance, self.output);
}
None
debug!("find_drop_glue_neighbors: {}", type_to_string(scx.tcx(), ty));
- // Make sure the exchange_free_fn() lang-item gets translated if
- // there is a boxed value.
- if let ty::TyBox(_) = ty.sty {
- let exchange_free_fn_def_id = scx.tcx()
- .lang_items
- .require(ExchangeFreeFnLangItem)
- .unwrap_or_else(|e| scx.sess().fatal(&e));
-
- assert!(can_have_local_instance(scx.tcx(), exchange_free_fn_def_id));
- let fn_substs = scx.empty_substs_for_def_id(exchange_free_fn_def_id);
- let exchange_free_fn_trans_item =
+ // Make sure the BoxFreeFn lang-item gets translated if there is a boxed value.
+ if let ty::TyBox(content_type) = ty.sty {
+ let def_id = scx.tcx().require_lang_item(BoxFreeFnLangItem);
+ assert!(can_have_local_instance(scx.tcx(), def_id));
+ let box_free_fn_trans_item =
create_fn_trans_item(scx,
- exchange_free_fn_def_id,
- fn_substs,
+ def_id,
+ scx.tcx().mk_substs(iter::once(Kind::from(content_type))),
scx.tcx().intern_substs(&[]));
- output.push(exchange_free_fn_trans_item);
+ output.push(box_free_fn_trans_item);
}
// If the type implements Drop, also add a translation item for the
}
}
+ fn visit_trait_item(&mut self, _: &'v hir::TraitItem) {
+ // Even if there's a default body with no explicit generics,
+ // it's still generic over some `Self: Trait`, so not a root.
+ }
+
fn visit_impl_item(&mut self, ii: &'v hir::ImplItem) {
match ii.node {
hir::ImplItemKind::Method(hir::MethodSig {
}
}
-// There are no translation items for constants themselves but their
-// initializers might still contain something that produces translation items,
-// such as cast that introduce a new vtable.
-fn collect_const_item_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
- def_id: DefId,
- substs: &'tcx Substs<'tcx>,
- output: &mut Vec<TransItem<'tcx>>)
+/// Scan the MIR in order to find function calls, closures, and drop-glue
+fn collect_neighbours<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
+ instance: Instance<'tcx>,
+ output: &mut Vec<TransItem<'tcx>>)
{
- // Scan the MIR in order to find function calls, closures, and
- // drop-glue
- let mir = scx.tcx().item_mir(def_id);
+ let mir = scx.tcx().item_mir(instance.def);
- let visitor = MirNeighborCollector {
+ let mut visitor = MirNeighborCollector {
scx: scx,
mir: &mir,
output: output,
- param_substs: substs
+ param_substs: instance.substs
};
- visit_mir_and_promoted(visitor, &mir);
-}
-
-fn visit_mir_and_promoted<'tcx, V: MirVisitor<'tcx>>(mut visitor: V, mir: &mir::Mir<'tcx>) {
visitor.visit_mir(&mir);
for promoted in &mir.promoted {
visitor.visit_mir(promoted);
&self.local().drop_glues
}
- pub fn local_node_for_inlined_defid<'a>(&'a self, def_id: DefId) -> Option<ast::NodeId> {
- self.sess().cstore.local_node_for_inlined_defid(def_id)
- }
-
- pub fn defid_for_inlined_node<'a>(&'a self, node_id: ast::NodeId) -> Option<DefId> {
- self.sess().cstore.defid_for_inlined_node(node_id)
- }
-
pub fn instances<'a>(&'a self) -> &'a RefCell<FxHashMap<Instance<'tcx>, ValueRef>> {
&self.local().instances
}
// Code relating to drop glue.
use std;
+use std::iter;
use llvm;
use llvm::{ValueRef, get_param};
-use middle::lang_items::ExchangeFreeFnLangItem;
+use middle::lang_items::BoxFreeFnLangItem;
use rustc::ty::subst::{Substs};
use rustc::traits;
use rustc::ty::{self, AdtKind, Ty, TypeFoldable};
-use adt;
+use rustc::ty::subst::Kind;
+use adt::{self, MaybeSizedValue};
use base::*;
use callee::Callee;
use common::*;
use syntax_pos::DUMMY_SP;
-pub fn trans_exchange_free_dyn<'a, 'tcx>(
+pub fn trans_exchange_free_ty<'a, 'tcx>(
bcx: &BlockAndBuilder<'a, 'tcx>,
- v: ValueRef,
- size: ValueRef,
- align: ValueRef
+ ptr: MaybeSizedValue,
+ content_ty: Ty<'tcx>
) {
- let def_id = langcall(bcx.tcx(), None, "", ExchangeFreeFnLangItem);
- let args = [bcx.pointercast(v, Type::i8p(bcx.ccx)), size, align];
- let callee = Callee::def(bcx.ccx, def_id, bcx.tcx().intern_substs(&[]));
+ let def_id = langcall(bcx.tcx(), None, "", BoxFreeFnLangItem);
+ let substs = bcx.tcx().mk_substs(iter::once(Kind::from(content_ty)));
+ let callee = Callee::def(bcx.ccx, def_id, substs);
- let ccx = bcx.ccx;
- let fn_ty = callee.direct_fn_type(ccx, &[]);
+ let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
- let llret = bcx.call(callee.reify(ccx), &args[..], None);
+ let llret = bcx.call(callee.reify(bcx.ccx),
+ &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize], None);
fn_ty.apply_attrs_callsite(llret);
}
-pub fn trans_exchange_free_ty<'a, 'tcx>(
- bcx: &BlockAndBuilder<'a, 'tcx>, ptr: ValueRef, content_ty: Ty<'tcx>
-) {
- assert!(bcx.ccx.shared().type_is_sized(content_ty));
- let sizing_type = sizing_type_of(bcx.ccx, content_ty);
- let content_size = llsize_of_alloc(bcx.ccx, sizing_type);
-
- // `Box<ZeroSizeType>` does not allocate.
- if content_size != 0 {
- let content_align = align_of(bcx.ccx, content_ty);
- let ccx = bcx.ccx;
- trans_exchange_free_dyn(bcx, ptr, C_uint(ccx, content_size), C_uint(ccx, content_align));
- }
-}
-
pub fn get_drop_glue_type<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Ty<'tcx> {
assert!(t.is_normalized_for_trans());
}
}
-fn drop_ty<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, v: ValueRef, t: Ty<'tcx>) {
- call_drop_glue(bcx, v, t, false, None)
+fn drop_ty<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>, args: MaybeSizedValue, t: Ty<'tcx>) {
+ call_drop_glue(bcx, args, t, false, None)
}
pub fn call_drop_glue<'a, 'tcx>(
bcx: &BlockAndBuilder<'a, 'tcx>,
- v: ValueRef,
+ mut args: MaybeSizedValue,
t: Ty<'tcx>,
skip_dtor: bool,
funclet: Option<&'a Funclet>,
};
let glue = get_drop_glue_core(ccx, g);
let glue_type = get_drop_glue_type(ccx.shared(), t);
- let ptr = if glue_type != t {
- bcx.pointercast(v, type_of(ccx, glue_type).ptr_to())
- } else {
- v
- };
+ if glue_type != t {
+ args.value = bcx.pointercast(args.value, type_of(ccx, glue_type).ptr_to());
+ }
// No drop-hint ==> call standard drop glue
- bcx.call(glue, &[ptr], funclet.map(|b| b.bundle()));
+ bcx.call(glue, &[args.value, args.meta][..1 + args.has_meta() as usize],
+ funclet.map(|b| b.bundle()));
}
}
let (llfn, _) = ccx.drop_glues().borrow().get(&g).unwrap().clone();
let fcx = FunctionContext::new(ccx, llfn);
- let bcx = fcx.get_entry_block();
+ let mut bcx = fcx.get_entry_block();
ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1);
// All glue functions take values passed *by alias*; this is a
// non-null, (and maybe we need to continue doing so), but we now
// must definitely check for special bit-patterns corresponding to
// the special dtor markings.
- let v0 = get_param(llfn, 0);
let t = g.ty();
+ let value = get_param(llfn, 0);
+ let ptr = if ccx.shared().type_is_sized(t) {
+ MaybeSizedValue::sized(value)
+ } else {
+ MaybeSizedValue::unsized_(value, get_param(llfn, 1))
+ };
+
let skip_dtor = match g {
DropGlueKind::Ty(_) => false,
DropGlueKind::TyContents(_) => true
// special. It may move to library and have Drop impl. As
// a safe-guard, assert TyBox not used with TyContents.
assert!(!skip_dtor);
- if !bcx.ccx.shared().type_is_sized(content_ty) {
- let llval = get_dataptr(&bcx, v0);
- let llbox = bcx.load(llval);
- drop_ty(&bcx, v0, content_ty);
- // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments
- let info = get_meta(&bcx, v0);
- let info = bcx.load(info);
- let (llsize, llalign) = size_and_align_of_dst(&bcx, content_ty, info);
-
- // `Box<ZeroSizeType>` does not allocate.
- let needs_free = bcx.icmp(llvm::IntNE, llsize, C_uint(bcx.ccx, 0u64));
- if const_to_opt_uint(needs_free) == Some(0) {
- bcx
- } else {
- let next_cx = bcx.fcx().build_new_block("next");
- let cond_cx = bcx.fcx().build_new_block("cond");
- bcx.cond_br(needs_free, cond_cx.llbb(), next_cx.llbb());
- trans_exchange_free_dyn(&cond_cx, llbox, llsize, llalign);
- cond_cx.br(next_cx.llbb());
- next_cx
- }
+ let ptr = if !bcx.ccx.shared().type_is_sized(content_ty) {
+ let llbox = bcx.load(get_dataptr(&bcx, ptr.value));
+ let info = bcx.load(get_meta(&bcx, ptr.value));
+ MaybeSizedValue::unsized_(llbox, info)
} else {
- let llval = v0;
- let llbox = bcx.load(llval);
- drop_ty(&bcx, llbox, content_ty);
- trans_exchange_free_ty(&bcx, llbox, content_ty);
- bcx
- }
+ MaybeSizedValue::sized(bcx.load(ptr.value))
+ };
+ drop_ty(&bcx, ptr, content_ty);
+ trans_exchange_free_ty(&bcx, ptr, content_ty);
+ bcx
}
ty::TyDynamic(..) => {
// No support in vtable for distinguishing destroying with
// versus without calling Drop::drop. Assert caller is
// okay with always calling the Drop impl, if any.
- // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments
assert!(!skip_dtor);
- let data_ptr = get_dataptr(&bcx, v0);
- let vtable_ptr = bcx.load(get_meta(&bcx, v0));
- let dtor = bcx.load(vtable_ptr);
- bcx.call(dtor, &[bcx.pointercast(bcx.load(data_ptr), Type::i8p(bcx.ccx))], None);
+ let dtor = bcx.load(ptr.meta);
+ bcx.call(dtor, &[ptr.value], None);
bcx
}
ty::TyAdt(def, ..) if def.dtor_kind().is_present() && !skip_dtor => {
- trans_custom_dtor(bcx, t, v0, def.is_union())
+ let shallow_drop = def.is_union();
+ let tcx = bcx.tcx();
+
+ let def = t.ty_adt_def().unwrap();
+
+ // Be sure to put the contents into a scope so we can use an invoke
+ // instruction to call the user destructor but still call the field
+ // destructors if the user destructor panics.
+ //
+ // FIXME (#14875) panic-in-drop semantics might be unsupported; we
+ // might well consider changing below to more direct code.
+ // Issue #23611: schedule cleanup of contents, re-inspecting the
+ // discriminant (if any) in case of variant swap in drop code.
+ let contents_scope = if !shallow_drop {
+ bcx.fcx().schedule_drop_adt_contents(ptr, t)
+ } else {
+ CleanupScope::noop()
+ };
+
+ let trait_ref = ty::Binder(ty::TraitRef {
+ def_id: tcx.lang_items.drop_trait().unwrap(),
+ substs: tcx.mk_substs_trait(t, &[])
+ });
+ let vtbl = match fulfill_obligation(bcx.ccx.shared(), DUMMY_SP, trait_ref) {
+ traits::VtableImpl(data) => data,
+ _ => bug!("dtor for {:?} is not an impl???", t)
+ };
+ let dtor_did = def.destructor().unwrap();
+ let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
+ let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
+ let llret;
+ let args = &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize];
+ if let Some(landing_pad) = contents_scope.landing_pad {
+ let normal_bcx = bcx.fcx().build_new_block("normal-return");
+ llret = bcx.invoke(callee.reify(ccx), args, normal_bcx.llbb(), landing_pad, None);
+ bcx = normal_bcx;
+ } else {
+ llret = bcx.call(callee.reify(bcx.ccx), args, None);
+ }
+ fn_ty.apply_attrs_callsite(llret);
+ contents_scope.trans(&bcx);
+ bcx
}
ty::TyAdt(def, ..) if def.is_union() => {
bcx
}
_ => {
if bcx.ccx.shared().type_needs_drop(t) {
- drop_structural_ty(bcx, v0, t)
+ drop_structural_ty(bcx, ptr, t)
} else {
bcx
}
bcx.ret_void();
}
-fn trans_custom_dtor<'a, 'tcx>(mut bcx: BlockAndBuilder<'a, 'tcx>,
- t: Ty<'tcx>,
- v0: ValueRef,
- shallow_drop: bool)
- -> BlockAndBuilder<'a, 'tcx>
-{
- debug!("trans_custom_dtor t: {}", t);
- let tcx = bcx.tcx();
-
- let def = t.ty_adt_def().unwrap();
-
- // Be sure to put the contents into a scope so we can use an invoke
- // instruction to call the user destructor but still call the field
- // destructors if the user destructor panics.
- //
- // FIXME (#14875) panic-in-drop semantics might be unsupported; we
- // might well consider changing below to more direct code.
- // Issue #23611: schedule cleanup of contents, re-inspecting the
- // discriminant (if any) in case of variant swap in drop code.
- let contents_scope = if !shallow_drop {
- bcx.fcx().schedule_drop_adt_contents(v0, t)
- } else {
- CleanupScope::noop()
- };
-
- let (sized_args, unsized_args);
- let args: &[ValueRef] = if bcx.ccx.shared().type_is_sized(t) {
- sized_args = [v0];
- &sized_args
- } else {
- // FIXME(#36457) -- we should pass unsized values to drop glue as two arguments
- unsized_args = [
- bcx.load(get_dataptr(&bcx, v0)),
- bcx.load(get_meta(&bcx, v0))
- ];
- &unsized_args
- };
-
- let trait_ref = ty::Binder(ty::TraitRef {
- def_id: tcx.lang_items.drop_trait().unwrap(),
- substs: tcx.mk_substs_trait(t, &[])
- });
- let vtbl = match fulfill_obligation(bcx.ccx.shared(), DUMMY_SP, trait_ref) {
- traits::VtableImpl(data) => data,
- _ => bug!("dtor for {:?} is not an impl???", t)
- };
- let dtor_did = def.destructor().unwrap();
- let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
- let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
- let llret;
- if let Some(landing_pad) = contents_scope.landing_pad {
- let normal_bcx = bcx.fcx().build_new_block("normal-return");
- llret = bcx.invoke(callee.reify(bcx.ccx), args, normal_bcx.llbb(), landing_pad, None);
- bcx = normal_bcx;
- } else {
- llret = bcx.call(callee.reify(bcx.ccx), args, None);
- }
- fn_ty.apply_attrs_callsite(llret);
- contents_scope.trans(&bcx);
- bcx
-}
-
pub fn size_and_align_of_dst<'a, 'tcx>(bcx: &BlockAndBuilder<'a, 'tcx>,
t: Ty<'tcx>, info: ValueRef)
-> (ValueRef, ValueRef) {
// Iterates through the elements of a structural type, dropping them.
fn drop_structural_ty<'a, 'tcx>(cx: BlockAndBuilder<'a, 'tcx>,
- av: ValueRef,
+ ptr: MaybeSizedValue,
t: Ty<'tcx>)
-> BlockAndBuilder<'a, 'tcx> {
fn iter_variant<'a, 'tcx>(cx: &BlockAndBuilder<'a, 'tcx>,
for (i, field) in variant.fields.iter().enumerate() {
let arg = monomorphize::field_ty(tcx, substs, field);
let field_ptr = adt::trans_field_ptr(&cx, t, av, Disr::from(variant.disr_val), i);
- drop_ty(&cx, field_ptr, arg);
+ drop_ty(&cx, MaybeSizedValue::sized(field_ptr), arg);
}
}
- let value = if cx.ccx.shared().type_is_sized(t) {
- adt::MaybeSizedValue::sized(av)
- } else {
- // FIXME(#36457) -- we should pass unsized values as two arguments
- let data = cx.load(get_dataptr(&cx, av));
- let info = cx.load(get_meta(&cx, av));
- adt::MaybeSizedValue::unsized_(data, info)
- };
-
let mut cx = cx;
match t.sty {
ty::TyClosure(def_id, substs) => {
for (i, upvar_ty) in substs.upvar_tys(def_id, cx.tcx()).enumerate() {
- let llupvar = adt::trans_field_ptr(&cx, t, value, Disr(0), i);
- drop_ty(&cx, llupvar, upvar_ty);
+ let llupvar = adt::trans_field_ptr(&cx, t, ptr, Disr(0), i);
+ drop_ty(&cx, MaybeSizedValue::sized(llupvar), upvar_ty);
}
}
ty::TyArray(_, n) => {
- let base = get_dataptr(&cx, value.value);
+ let base = get_dataptr(&cx, ptr.value);
let len = C_uint(cx.ccx, n);
let unit_ty = t.sequence_element_type(cx.tcx());
- cx = tvec::slice_for_each(&cx, base, unit_ty, len, |bb, vv| drop_ty(bb, vv, unit_ty));
+ cx = tvec::slice_for_each(&cx, base, unit_ty, len,
+ |bb, vv| drop_ty(bb, MaybeSizedValue::sized(vv), unit_ty));
}
ty::TySlice(_) | ty::TyStr => {
let unit_ty = t.sequence_element_type(cx.tcx());
- cx = tvec::slice_for_each(&cx, value.value, unit_ty, value.meta,
- |bb, vv| drop_ty(bb, vv, unit_ty));
+ cx = tvec::slice_for_each(&cx, ptr.value, unit_ty, ptr.meta,
+ |bb, vv| drop_ty(bb, MaybeSizedValue::sized(vv), unit_ty));
}
ty::TyTuple(ref args) => {
for (i, arg) in args.iter().enumerate() {
- let llfld_a = adt::trans_field_ptr(&cx, t, value, Disr(0), i);
- drop_ty(&cx, llfld_a, *arg);
+ let llfld_a = adt::trans_field_ptr(&cx, t, ptr, Disr(0), i);
+ drop_ty(&cx, MaybeSizedValue::sized(llfld_a), *arg);
}
}
ty::TyAdt(adt, substs) => match adt.adt_kind() {
AdtKind::Struct => {
let VariantInfo { fields, discr } = VariantInfo::from_ty(cx.tcx(), t, None);
for (i, &Field(_, field_ty)) in fields.iter().enumerate() {
- let llfld_a = adt::trans_field_ptr(&cx, t, value, Disr::from(discr), i);
-
- let val = if cx.ccx.shared().type_is_sized(field_ty) {
- llfld_a
+ let llfld_a = adt::trans_field_ptr(&cx, t, ptr, Disr::from(discr), i);
+ let ptr = if cx.ccx.shared().type_is_sized(field_ty) {
+ MaybeSizedValue::sized(llfld_a)
} else {
- // FIXME(#36457) -- we should pass unsized values as two arguments
- let scratch = alloc_ty(&cx, field_ty, "__fat_ptr_iter");
- cx.store(llfld_a, get_dataptr(&cx, scratch));
- cx.store(value.meta, get_meta(&cx, scratch));
- scratch
+ MaybeSizedValue::unsized_(llfld_a, ptr.meta)
};
- drop_ty(&cx, val, field_ty);
+ drop_ty(&cx, ptr, field_ty);
}
}
AdtKind::Union => {
// NB: we must hit the discriminant first so that structural
// comparison know not to proceed when the discriminants differ.
- match adt::trans_switch(&cx, t, av, false) {
+ match adt::trans_switch(&cx, t, ptr.value, false) {
(adt::BranchKind::Single, None) => {
if n_variants != 0 {
assert!(n_variants == 1);
- iter_variant(&cx, t, adt::MaybeSizedValue::sized(av),
- &adt.variants[0], substs);
+ iter_variant(&cx, t, ptr, &adt.variants[0], substs);
}
}
(adt::BranchKind::Switch, Some(lldiscrim_a)) => {
let tcx = cx.tcx();
- drop_ty(&cx, lldiscrim_a, tcx.types.isize);
+ drop_ty(&cx, MaybeSizedValue::sized(lldiscrim_a), tcx.types.isize);
// Create a fall-through basic block for the "else" case of
// the switch instruction we're about to generate. Note that
let variant_cx = cx.fcx().build_new_block(&variant_cx_name);
let case_val = adt::trans_case(&cx, t, Disr::from(variant.disr_val));
variant_cx.add_case(llswitch, case_val, variant_cx.llbb());
- iter_variant(&variant_cx, t, value, variant, substs);
+ iter_variant(&variant_cx, t, ptr, variant, substs);
variant_cx.br(next_cx.llbb());
}
cx = next_cx;
mod cabi_mips;
mod cabi_mips64;
mod cabi_msp430;
+mod cabi_nvptx;
+mod cabi_nvptx64;
mod cabi_powerpc;
mod cabi_powerpc64;
mod cabi_s390x;
+mod cabi_sparc;
mod cabi_x86;
mod cabi_x86_64;
mod cabi_x86_win64;
use rustc::ty::{self, layout};
use rustc::mir;
use abi::{Abi, FnType, ArgType};
-use adt;
+use adt::{self, MaybeSizedValue};
use base::{self, Lifetime};
use callee::{Callee, CalleeData, Fn, Intrinsic, NamedTupleConstructor, Virtual};
use common::{self, BlockAndBuilder, Funclet};
use super::operand::OperandRef;
use super::operand::OperandValue::{Pair, Ref, Immediate};
-use std::ptr;
-
impl<'a, 'tcx> MirContext<'a, 'tcx> {
pub fn trans_block(&mut self, bb: mir::BasicBlock,
funclets: &IndexVec<mir::BasicBlock, Option<Funclet>>) {
let lvalue = self.trans_lvalue(&bcx, location);
let drop_fn = glue::get_drop_glue(bcx.ccx, ty);
let drop_ty = glue::get_drop_glue_type(bcx.ccx.shared(), ty);
- let is_sized = bcx.ccx.shared().type_is_sized(ty);
- let llvalue = if is_sized {
- if drop_ty != ty {
+ let ptr = if bcx.ccx.shared().type_is_sized(ty) {
+ let value = if drop_ty != ty {
bcx.pointercast(lvalue.llval, type_of::type_of(bcx.ccx, drop_ty).ptr_to())
} else {
lvalue.llval
- }
+ };
+ MaybeSizedValue::sized(value)
} else {
- // FIXME(#36457) Currently drop glue takes sized
- // values as a `*(data, meta)`, but elsewhere in
- // MIR we pass `(data, meta)` as two separate
- // arguments. It would be better to fix drop glue,
- // but I am shooting for a quick fix to #35546
- // here that can be cleanly backported to beta, so
- // I want to avoid touching all of trans.
- let scratch = base::alloc_ty(&bcx, ty, "drop");
- Lifetime::Start.call(&bcx, scratch);
- bcx.store(lvalue.llval, base::get_dataptr(&bcx, scratch));
- bcx.store(lvalue.llextra, base::get_meta(&bcx, scratch));
- scratch
+ MaybeSizedValue::unsized_(lvalue.llval, lvalue.llextra)
};
+ let args = &[ptr.value, ptr.meta][..1 + ptr.has_meta() as usize];
if let Some(unwind) = unwind {
- bcx.invoke(drop_fn,
- &[llvalue],
- self.blocks[target],
- llblock(self, unwind),
- cleanup_bundle);
+ bcx.invoke(
+ drop_fn,
+ args,
+ self.blocks[target],
+ llblock(self, unwind),
+ cleanup_bundle
+ );
} else {
- bcx.call(drop_fn, &[llvalue], cleanup_bundle);
+ bcx.call(drop_fn, args, cleanup_bundle);
funclet_br(self, bcx, target);
}
}
}
_ => None
};
- let intrinsic = intrinsic.as_ref().map(|s| &s[..]);
+ let mut intrinsic = intrinsic.as_ref().map(|s| &s[..]);
if intrinsic == Some("move_val_init") {
let &(_, target) = destination.as_ref().unwrap();
return;
}
- // FIXME: This should proxy to the drop glue in the future when the ABI matches;
- // most of the below code was copied from the match arm for TerminatorKind::Drop.
- if intrinsic == Some("drop_in_place") {
- let &(_, target) = destination.as_ref().unwrap();
- let ty = if let ty::TyFnDef(_, substs, _) = callee.ty.sty {
- substs.type_at(0)
- } else {
- bug!("Unexpected ty: {}", callee.ty);
- };
-
- // Double check for necessity to drop
- if !bcx.ccx.shared().type_needs_drop(ty) {
- funclet_br(self, bcx, target);
- return;
- }
-
- let ptr = self.trans_operand(&bcx, &args[0]);
- let (llval, llextra) = match ptr.val {
- Immediate(llptr) => (llptr, ptr::null_mut()),
- Pair(llptr, llextra) => (llptr, llextra),
- Ref(_) => bug!("Deref of by-Ref type {:?}", ptr.ty)
- };
-
- let drop_fn = glue::get_drop_glue(bcx.ccx, ty);
- let drop_ty = glue::get_drop_glue_type(bcx.ccx.shared(), ty);
- let is_sized = bcx.ccx.shared().type_is_sized(ty);
- let llvalue = if is_sized {
- if drop_ty != ty {
- bcx.pointercast(llval, type_of::type_of(bcx.ccx, drop_ty).ptr_to())
- } else {
- llval
- }
- } else {
- // FIXME(#36457) Currently drop glue takes sized
- // values as a `*(data, meta)`, but elsewhere in
- // MIR we pass `(data, meta)` as two separate
- // arguments. It would be better to fix drop glue,
- // but I am shooting for a quick fix to #35546
- // here that can be cleanly backported to beta, so
- // I want to avoid touching all of trans.
- let scratch = base::alloc_ty(&bcx, ty, "drop");
- Lifetime::Start.call(&bcx, scratch);
- bcx.store(llval, base::get_dataptr(&bcx, scratch));
- bcx.store(llextra, base::get_meta(&bcx, scratch));
- scratch
- };
- if let Some(unwind) = *cleanup {
- bcx.invoke(drop_fn,
- &[llvalue],
- self.blocks[target],
- llblock(self, unwind),
- cleanup_bundle);
- } else {
- bcx.call(drop_fn, &[llvalue], cleanup_bundle);
- funclet_br(self, bcx, target);
- }
- return;
- }
-
if intrinsic == Some("transmute") {
let &(ref dest, target) = destination.as_ref().unwrap();
self.with_lvalue_ref(&bcx, dest, |this, dest| {
}).collect::<Vec<_>>();
let fn_ty = callee.direct_fn_type(bcx.ccx, &extra_args);
+ if intrinsic == Some("drop_in_place") {
+ let &(_, target) = destination.as_ref().unwrap();
+ let ty = if let ty::TyFnDef(_, substs, _) = callee.ty.sty {
+ substs.type_at(0)
+ } else {
+ bug!("Unexpected ty: {}", callee.ty);
+ };
+
+ // Double check for necessity to drop
+ if !bcx.ccx.shared().type_needs_drop(ty) {
+ funclet_br(self, bcx, target);
+ return;
+ }
+
+ let drop_fn = glue::get_drop_glue(bcx.ccx, ty);
+ let llty = fn_ty.llvm_type(bcx.ccx).ptr_to();
+ callee.data = Fn(bcx.pointercast(drop_fn, llty));
+ intrinsic = None;
+ }
+
// The arguments we'll be passing. Plus one to account for outptr, if used.
let arg_count = fn_ty.args.len() + fn_ty.ret.is_indirect() as usize;
let mut llargs = Vec::with_capacity(arg_count);
use rustc::infer::TransNormalize;
use rustc::mir;
use rustc::mir::tcx::LvalueTy;
-use rustc::traits;
use rustc::ty::{self, Ty, TyCtxt, TypeFoldable};
use rustc::ty::cast::{CastTy, IntTy};
use rustc::ty::subst::Substs;
use value::Value;
use syntax::ast;
-use syntax_pos::{Span, DUMMY_SP};
+use syntax_pos::Span;
use std::fmt;
use std::ptr;
}
fn trans_def(ccx: &'a CrateContext<'a, 'tcx>,
- mut instance: Instance<'tcx>,
+ instance: Instance<'tcx>,
args: IndexVec<mir::Local, Const<'tcx>>)
-> Result<Const<'tcx>, ConstEvalErr> {
- // Try to resolve associated constants.
- if let Some(trait_id) = ccx.tcx().trait_of_item(instance.def) {
- let trait_ref = ty::TraitRef::new(trait_id, instance.substs);
- let trait_ref = ty::Binder(trait_ref);
- let vtable = common::fulfill_obligation(ccx.shared(), DUMMY_SP, trait_ref);
- if let traits::VtableImpl(vtable_impl) = vtable {
- let name = ccx.tcx().item_name(instance.def);
- let ac = ccx.tcx().associated_items(vtable_impl.impl_def_id)
- .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
- if let Some(ac) = ac {
- instance = Instance::new(ac.def_id, vtable_impl.substs);
- }
- }
- }
-
+ let instance = instance.resolve_const(ccx.shared());
let mir = ccx.tcx().item_mir(instance.def);
MirConstContext::new(ccx, &mir, instance.substs, args).trans()
}
use common::*;
use rustc::hir::def_id::DefId;
use rustc::infer::TransNormalize;
+use rustc::traits;
use rustc::ty::fold::{TypeFolder, TypeFoldable};
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::util::ppaux;
use rustc::util::common::MemoizationMap;
+
+use syntax::codemap::DUMMY_SP;
+
use std::fmt;
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
}
}
-impl<'tcx> Instance<'tcx> {
+impl<'a, 'tcx> Instance<'tcx> {
pub fn new(def_id: DefId, substs: &'tcx Substs<'tcx>)
-> Instance<'tcx> {
assert!(substs.regions().all(|&r| r == ty::ReErased));
Instance { def: def_id, substs: substs }
}
- pub fn mono<'a>(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
+
+ pub fn mono(scx: &SharedCrateContext<'a, 'tcx>, def_id: DefId) -> Instance<'tcx> {
Instance::new(def_id, scx.empty_substs_for_def_id(def_id))
}
+
+ /// For associated constants from traits, return the impl definition.
+ pub fn resolve_const(&self, scx: &SharedCrateContext<'a, 'tcx>) -> Self {
+ if let Some(trait_id) = scx.tcx().trait_of_item(self.def) {
+ let trait_ref = ty::TraitRef::new(trait_id, self.substs);
+ let trait_ref = ty::Binder(trait_ref);
+ let vtable = fulfill_obligation(scx, DUMMY_SP, trait_ref);
+ if let traits::VtableImpl(vtable_impl) = vtable {
+ let name = scx.tcx().item_name(self.def);
+ let ac = scx.tcx().associated_items(vtable_impl.impl_def_id)
+ .find(|item| item.kind == ty::AssociatedKind::Const && item.name == name);
+ if let Some(ac) = ac {
+ return Instance::new(ac.def_id, vtable_impl.substs);
+ }
+ }
+ }
+
+ *self
+ }
}
/// Monomorphizes a type from the AST by first applying the in-scope
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(tcx.types.i8)), tcx.mk_nil(), false);
+ let sig = tcx.mk_fn_sig(iter::once(tcx.mk_mut_ptr(t)), tcx.mk_nil(), false);
- // Create a FnType for fn(*mut i8) and substitute the real type in
- // later - that prevents FnType from splitting fat pointers up.
- let mut fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
- fn_ty.args[0].original_ty = type_of::type_of(ccx, t).ptr_to();
+ debug!("predefine_drop_glue: sig={}", sig);
+
+ let fn_ty = FnType::new(ccx, Abi::Rust, &sig, &[]);
let llfnty = fn_ty.llvm_type(ccx);
assert!(declare::get_defined_value(ccx, symbol_name).is_none());
use rustc_const_eval::eval_length;
use rustc_data_structures::accumulate_vec::AccumulateVec;
-use hir::{self, SelfKind};
+use hir;
use hir::def::Def;
use hir::def_id::DefId;
-use hir::print as pprust;
use middle::resolve_lifetime as rl;
use rustc::lint;
use rustc::ty::subst::{Kind, Subst, Substs};
}
fn report_elision_failure(
+ tcx: TyCtxt,
db: &mut DiagnosticBuilder,
params: Vec<ElisionFailureInfo>)
{
for (i, info) in elided_params.into_iter().enumerate() {
let ElisionFailureInfo {
- name, lifetime_count: n, have_bound_regions
+ parent, index, lifetime_count: n, have_bound_regions
} = info;
- let help_name = if name.is_empty() {
- format!("argument {}", i + 1)
+ let help_name = if let Some(body) = parent {
+ let arg = &tcx.map.body(body).arguments[index];
+ format!("`{}`", tcx.map.node_to_pretty_string(arg.pat.id))
} else {
- format!("`{}`", name)
+ format!("argument {}", index + 1)
};
m.push_str(&(if n == 1 {
err.span_label(ampersand_span, &format!("expected lifetime parameter"));
if let Some(params) = params {
- report_elision_failure(&mut err, params);
+ report_elision_failure(self.tcx(), &mut err, params);
}
err.emit();
ty::ReStatic
/// corresponding to each input type/pattern.
fn find_implied_output_region<I>(&self,
input_tys: &[Ty<'tcx>],
- input_pats: I) -> ElidedLifetime
- where I: Iterator<Item=String>
+ parent: Option<hir::BodyId>,
+ input_indices: I) -> ElidedLifetime
+ where I: Iterator<Item=usize>
{
let tcx = self.tcx();
let mut lifetimes_for_params = Vec::with_capacity(input_tys.len());
let mut possible_implied_output_region = None;
let mut lifetimes = 0;
- for input_type in input_tys.iter() {
+ for (input_type, index) in input_tys.iter().zip(input_indices) {
let mut regions = FxHashSet();
let have_bound_regions = tcx.collect_regions(input_type, &mut regions);
possible_implied_output_region = regions.iter().cloned().next();
}
- // Use a placeholder for `name` because computing it can be
- // expensive and we don't want to do it until we know it's
- // necessary.
lifetimes_for_params.push(ElisionFailureInfo {
- name: String::new(),
+ parent: parent,
+ index: index,
lifetime_count: regions.len(),
have_bound_regions: have_bound_regions
});
if lifetimes == 1 {
Ok(*possible_implied_output_region.unwrap())
} else {
- // Fill in the expensive `name` fields now that we know they're
- // needed.
- for (info, input_pat) in lifetimes_for_params.iter_mut().zip(input_pats) {
- info.name = input_pat;
- }
Err(Some(lifetimes_for_params))
}
}
let inputs = self.tcx().mk_type_list(data.inputs.iter().map(|a_t| {
self.ast_ty_arg_to_ty(&binding_rscope, None, region_substs, a_t)
}));
- let input_params = iter::repeat(String::new()).take(inputs.len());
- let implied_output_region = self.find_implied_output_region(&inputs, input_params);
+ let input_params = 0..inputs.len();
+ let implied_output_region = self.find_implied_output_region(&inputs, None, input_params);
let (output, output_span) = match data.output {
Some(ref output_ty) => {
}
_ => {
span_fatal!(self.tcx().sess, path.span, E0245, "`{}` is not a trait",
- path);
+ self.tcx().map.node_to_pretty_string(trait_ref.ref_id));
}
}
}
let mut err = struct_span_err!(tcx.sess, ty.span, E0178,
"expected a path on the left-hand side \
of `+`, not `{}`",
- pprust::ty_to_string(ty));
+ tcx.map.node_to_pretty_string(ty.id));
err.span_label(ty.span, &format!("expected a path"));
let hi = bounds.iter().map(|x| match *x {
hir::TraitTyParamBound(ref tr, _) => tr.span.hi,
expn_id: ty.span.expn_id,
});
match (&ty.node, full_span) {
- (&hir::TyRptr(None, ref mut_ty), Some(full_span)) => {
- let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
+ (&hir::TyRptr(ref lifetime, ref mut_ty), Some(full_span)) => {
+ let ty_str = hir::print::to_string(&tcx.map, |s| {
+ use syntax::print::pp::word;
+ use syntax::print::pprust::PrintState;
+
+ word(&mut s.s, "&")?;
+ s.print_opt_lifetime(lifetime)?;
+ s.print_mutability(mut_ty.mutbl)?;
+ s.popen()?;
+ s.print_type(&mut_ty.ty)?;
+ s.print_bounds(" +", bounds)?;
+ s.pclose()
+ });
err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
- format!("&{}({} +{})",
- mutbl_str,
- pprust::ty_to_string(&mut_ty.ty),
- pprust::bounds_to_string(bounds)));
- }
- (&hir::TyRptr(Some(ref lt), ref mut_ty), Some(full_span)) => {
- let mutbl_str = if mut_ty.mutbl == hir::MutMutable { "mut " } else { "" };
- err.span_suggestion(full_span, "try adding parentheses (per RFC 438):",
- format!("&{} {}({} +{})",
- pprust::lifetime_to_string(lt),
- mutbl_str,
- pprust::ty_to_string(&mut_ty.ty),
- pprust::bounds_to_string(bounds)));
+ ty_str);
}
_ => {
self.set_tainted_by_errors();
return self.tcx().types.err;
}
- _ => {
- struct_span_err!(tcx.sess, span, E0248,
- "found value `{}` used as a type",
- tcx.item_path_str(path.def.def_id()))
- .span_label(span, &format!("value used as a type"))
- .emit();
- return self.tcx().types.err;
- }
+ _ => span_bug!(span, "unexpected definition: {:?}", path.def)
}
}
bf.abi,
None,
&bf.decl,
+ None,
anon_scope,
anon_scope);
};
self.associated_path_def_to_ty(ast_ty.id, ast_ty.span, ty, def, segment).0
}
- hir::TyArray(ref ty, ref e) => {
- if let Ok(length) = eval_length(tcx.global_tcx(), &e, "array length") {
+ hir::TyArray(ref ty, length) => {
+ let e = &tcx.map.body(length).value;
+ if let Ok(length) = eval_length(tcx.global_tcx(), e, "array length") {
tcx.mk_array(self.ast_ty_to_ty(rscope, &ty), length)
} else {
self.tcx().types.err
pub fn ty_of_arg(&self,
rscope: &RegionScope,
- a: &hir::Arg,
+ ty: &hir::Ty,
expected_ty: Option<Ty<'tcx>>)
-> Ty<'tcx>
{
- match a.ty.node {
+ match ty.node {
hir::TyInfer if expected_ty.is_some() => expected_ty.unwrap(),
- hir::TyInfer => self.ty_infer(a.ty.span),
- _ => self.ast_ty_to_ty(rscope, &a.ty),
+ hir::TyInfer => self.ty_infer(ty.span),
+ _ => self.ast_ty_to_ty(rscope, ty),
}
}
pub fn ty_of_method(&self,
sig: &hir::MethodSig,
- untransformed_self_ty: Ty<'tcx>,
+ opt_self_value_ty: Option<Ty<'tcx>>,
+ body: Option<hir::BodyId>,
anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx> {
self.ty_of_method_or_bare_fn(sig.unsafety,
sig.abi,
- Some(untransformed_self_ty),
+ opt_self_value_ty,
&sig.decl,
+ body,
None,
anon_scope)
}
unsafety: hir::Unsafety,
abi: abi::Abi,
decl: &hir::FnDecl,
+ body: hir::BodyId,
anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx> {
- self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, None, anon_scope)
+ self.ty_of_method_or_bare_fn(unsafety, abi, None, decl, Some(body), None, anon_scope)
}
fn ty_of_method_or_bare_fn(&self,
unsafety: hir::Unsafety,
abi: abi::Abi,
- opt_untransformed_self_ty: Option<Ty<'tcx>>,
+ opt_self_value_ty: Option<Ty<'tcx>>,
decl: &hir::FnDecl,
+ body: Option<hir::BodyId>,
arg_anon_scope: Option<AnonTypeScope>,
ret_anon_scope: Option<AnonTypeScope>)
-> &'tcx ty::BareFnTy<'tcx>
// declaration are bound to that function type.
let rb = MaybeWithAnonTypes::new(BindingRscope::new(), arg_anon_scope);
- // `implied_output_region` is the region that will be assumed for any
- // region parameters in the return type. In accordance with the rules for
- // lifetime elision, we can determine it in two ways. First (determined
- // here), if self is by-reference, then the implied output region is the
- // region of the self parameter.
- let (self_ty, explicit_self) = match (opt_untransformed_self_ty, decl.get_self()) {
- (Some(untransformed_self_ty), Some(explicit_self)) => {
- let self_type = self.determine_self_type(&rb, untransformed_self_ty,
- &explicit_self);
- (Some(self_type), Some(ExplicitSelf::determine(untransformed_self_ty, self_type)))
- }
- _ => (None, None),
- };
+ let input_tys: Vec<Ty> =
+ decl.inputs.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
- // HACK(eddyb) replace the fake self type in the AST with the actual type.
- let arg_params = if self_ty.is_some() {
- &decl.inputs[1..]
- } else {
- &decl.inputs[..]
- };
- let arg_tys: Vec<Ty> =
- arg_params.iter().map(|a| self.ty_of_arg(&rb, a, None)).collect();
+ let has_self = opt_self_value_ty.is_some();
+ let explicit_self = opt_self_value_ty.map(|self_value_ty| {
+ ExplicitSelf::determine(self_value_ty, input_tys[0])
+ });
- // Second, if there was exactly one lifetime (either a substitution or a
- // reference) in the arguments, then any anonymous regions in the output
- // have that lifetime.
let implied_output_region = match explicit_self {
+ // `implied_output_region` is the region that will be assumed for any
+ // region parameters in the return type. In accordance with the rules for
+ // lifetime elision, we can determine it in two ways. First (determined
+ // here), if self is by-reference, then the implied output region is the
+ // region of the self parameter.
Some(ExplicitSelf::ByReference(region, _)) => Ok(*region),
+
+ // Second, if there was exactly one lifetime (either a substitution or a
+ // reference) in the arguments, then any anonymous regions in the output
+ // have that lifetime.
_ => {
- self.find_implied_output_region(&arg_tys,
- arg_params.iter()
- .map(|a| pprust::pat_to_string(&a.pat)))
+ let arg_tys = &input_tys[has_self as usize..];
+ let arg_params = has_self as usize..input_tys.len();
+ self.find_implied_output_region(arg_tys, body, arg_params)
}
};
unsafety: unsafety,
abi: abi,
sig: ty::Binder(self.tcx().mk_fn_sig(
- self_ty.into_iter().chain(arg_tys),
+ input_tys.into_iter(),
output_ty,
decl.variadic
)),
})
}
- fn determine_self_type<'a>(&self,
- rscope: &RegionScope,
- untransformed_self_ty: Ty<'tcx>,
- explicit_self: &hir::ExplicitSelf)
- -> Ty<'tcx>
- {
- match explicit_self.node {
- SelfKind::Value(..) => untransformed_self_ty,
- SelfKind::Region(ref lifetime, mutability) => {
- let region =
- self.opt_ast_region_to_region(
- rscope,
- explicit_self.span,
- lifetime);
- self.tcx().mk_ref(region,
- ty::TypeAndMut {
- ty: untransformed_self_ty,
- mutbl: mutability
- })
- }
- SelfKind::Explicit(ref ast_type, _) => self.ast_ty_to_ty(rscope, &ast_type)
- }
- }
-
pub fn ty_of_closure(&self,
unsafety: hir::Unsafety,
decl: &hir::FnDecl,
let report_unexpected_def = |def: Def| {
span_err!(tcx.sess, pat.span, E0533,
"expected unit struct/variant or constant, found {} `{}`",
- def.kind_name(), qpath);
+ def.kind_name(),
+ hir::print::to_string(&tcx.map, |s| s.print_qpath(qpath, false)));
};
// Resolve the path and check the definition for errors.
};
let report_unexpected_def = |def: Def| {
let msg = format!("expected tuple struct/variant, found {} `{}`",
- def.kind_name(), qpath);
+ def.kind_name(),
+ hir::print::to_string(&tcx.map, |s| s.print_qpath(qpath, false)));
struct_span_err!(tcx.sess, pat.span, E0164, "{}", msg)
.span_label(pat.span, &format!("not a tuple variant or struct")).emit();
on_error();
use CrateCtxt;
use hir::def::Def;
use hir::def_id::{DefId, LOCAL_CRATE};
-use hir::print;
use rustc::{infer, traits};
use rustc::ty::{self, LvaluePreference, Ty};
use syntax::symbol::Symbol;
if let &ty::TyAdt(adt_def, ..) = t {
if adt_def.is_enum() {
if let hir::ExprCall(ref expr, _) = call_expr.node {
- unit_variant = Some(print::expr_to_string(expr))
+ unit_variant = Some(self.tcx.map.node_to_pretty_string(expr.id))
}
}
}
expr: &hir::Expr,
_capture: hir::CaptureClause,
decl: &'gcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
expected: Expectation<'tcx>)
-> Ty<'tcx> {
debug!("check_expr_closure(expr={:?},expected={:?})",
Some(ty) => self.deduce_expectations_from_expected_type(ty),
None => (None, None),
};
- let body = self.tcx.map.expr(body_id);
+ let body = self.tcx.map.body(body_id);
self.check_closure(expr, expected_kind, decl, body, expected_sig)
}
expr: &hir::Expr,
opt_kind: Option<ty::ClosureKind>,
decl: &'gcx hir::FnDecl,
- body: &'gcx hir::Expr,
+ body: &'gcx hir::Body,
expected_sig: Option<ty::FnSig<'tcx>>)
-> Ty<'tcx> {
debug!("check_closure opt_kind={:?} expected_sig={:?}",
debug!("check_closure: expr.id={:?} closure_type={:?}", expr.id, closure_type);
- let fn_sig = self.tcx
- .liberate_late_bound_regions(self.tcx.region_maps.call_site_extent(expr.id, body.id),
- &fn_ty.sig);
- let fn_sig = (**self).normalize_associated_types_in(body.span, body.id, &fn_sig);
+ 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.inh.normalize_associated_types_in(body.value.span,
+ body.value.id, &fn_sig);
check_fn(self,
hir::Unsafety::Normal,
&fn_sig,
decl,
expr.id,
- &body);
+ body);
// Tuple up the arguments and insert the resulting function type into
// the `closures` table.
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-use rustc::hir;
+use rustc::hir::{self, ImplItemKind, TraitItemKind};
use rustc::infer::{self, InferOk};
use rustc::middle::free_region::FreeRegionMap;
use rustc::ty;
use rustc::traits::{self, ObligationCause, ObligationCauseCode, Reveal};
use rustc::ty::error::{ExpectedFound, TypeError};
use rustc::ty::subst::{Subst, Substs};
-use rustc::hir::{ImplItemKind, TraitItem_, Ty_};
use rustc::util::common::ErrorReported;
use syntax::ast;
TypeError::Mutability => {
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
let trait_m_iter = match tcx.map.expect_trait_item(trait_m_node_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+ TraitItemKind::Method(ref trait_m_sig, _) => {
trait_m_sig.decl.inputs.iter()
}
- _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+ _ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
};
- impl_m_iter.zip(trait_m_iter)
- .find(|&(ref impl_arg, ref trait_arg)| {
- match (&impl_arg.ty.node, &trait_arg.ty.node) {
- (&Ty_::TyRptr(_, ref impl_mt), &Ty_::TyRptr(_, ref trait_mt)) |
- (&Ty_::TyPtr(ref impl_mt), &Ty_::TyPtr(ref trait_mt)) => {
- impl_mt.mutbl != trait_mt.mutbl
- }
- _ => false,
- }
- })
- .map(|(ref impl_arg, ref trait_arg)| {
- match (impl_arg.to_self(), trait_arg.to_self()) {
- (Some(impl_self), Some(trait_self)) => {
- (impl_self.span, Some(trait_self.span))
- }
- (None, None) => (impl_arg.ty.span, Some(trait_arg.ty.span)),
- _ => {
- bug!("impl and trait fns have different first args, impl: \
- {:?}, trait: {:?}",
- impl_arg,
- trait_arg)
- }
- }
- })
- .unwrap_or((cause.span, tcx.map.span_if_local(trait_m.def_id)))
+ impl_m_iter.zip(trait_m_iter).find(|&(ref impl_arg, ref trait_arg)| {
+ match (&impl_arg.node, &trait_arg.node) {
+ (&hir::TyRptr(_, ref impl_mt), &hir::TyRptr(_, ref trait_mt)) |
+ (&hir::TyPtr(ref impl_mt), &hir::TyPtr(ref trait_mt)) => {
+ impl_mt.mutbl != trait_mt.mutbl
+ }
+ _ => false,
+ }
+ }).map(|(ref impl_arg, ref trait_arg)| {
+ (impl_arg.span, Some(trait_arg.span))
+ })
+ .unwrap_or_else(|| (cause.span, tcx.map.span_if_local(trait_m.def_id)))
} else {
(cause.span, tcx.map.span_if_local(trait_m.def_id))
}
if let Some(trait_m_node_id) = tcx.map.as_local_node_id(trait_m.def_id) {
let (trait_m_output, trait_m_iter) =
match tcx.map.expect_trait_item(trait_m_node_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+ TraitItemKind::Method(ref trait_m_sig, _) => {
(&trait_m_sig.decl.output, trait_m_sig.decl.inputs.iter())
}
- _ => bug!("{:?} is not a MethodTraitItem", trait_m),
+ _ => bug!("{:?} is not a TraitItemKind::Method", trait_m),
};
let impl_iter = impl_sig.inputs().iter();
.filter_map(|(((impl_arg_ty, trait_arg_ty), impl_arg), trait_arg)| {
match infcx.sub_types(true, &cause, trait_arg_ty, impl_arg_ty) {
Ok(_) => None,
- Err(_) => Some((impl_arg.ty.span, Some(trait_arg.ty.span))),
+ Err(_) => Some((impl_arg.span, Some(trait_arg.span))),
}
})
.next()
let trait_m_node_id = tcx.map.as_local_node_id(trait_m.def_id);
let trait_span = if let Some(trait_id) = trait_m_node_id {
match tcx.map.expect_trait_item(trait_id).node {
- TraitItem_::MethodTraitItem(ref trait_m_sig, _) => {
+ TraitItemKind::Method(ref trait_m_sig, _) => {
if let Some(arg) = trait_m_sig.decl.inputs.get(if trait_number_args > 0 {
trait_number_args - 1
} else {
0
}) {
- Some(arg.pat.span)
+ Some(arg.span)
} else {
trait_item_span
}
} else {
0
}) {
- arg.pat.span
+ arg.span
} else {
impl_m_span
}
// Add a label to the Span containing just the type of the item
let trait_c_node_id = tcx.map.as_local_node_id(trait_c.def_id).unwrap();
let trait_c_span = match tcx.map.expect_trait_item(trait_c_node_id).node {
- TraitItem_::ConstTraitItem(ref ty, _) => ty.span,
+ TraitItemKind::Const(ref ty, _) => ty.span,
_ => bug!("{:?} is not a trait const", trait_c),
};
let i_n_tps = tcx.item_generics(def_id).types.len();
if i_n_tps != n_tps {
let span = match it.node {
- hir::ForeignItemFn(_, ref generics) => generics.span,
+ hir::ForeignItemFn(_, _, ref generics) => generics.span,
hir::ForeignItemStatic(..) => it.span
};
self.tcx.check_stability(def.def_id(), expr_id, span);
if let probe::InherentImplPick = pick.kind {
- if !pick.item.vis.is_accessible_from(self.body_id, &self.tcx.map) {
+ if !self.tcx.vis_is_accessible_from(pick.item.vis, self.body_id) {
let msg = format!("{} `{}` is private", def.kind_name(), method_name);
self.tcx.sess.span_err(span, &msg);
}
continue
}
- if !item.vis.is_accessible_from(self.body_id, &self.tcx.map) {
+ if !self.tcx.vis_is_accessible_from(item.vis, self.body_id) {
self.private_candidate = Some(item.def());
continue
}
use errors::DiagnosticBuilder;
use syntax_pos::Span;
-use rustc::hir::print as pprust;
use rustc::hir;
use rustc::infer::type_variable::TypeVariableOrigin;
let msg = if let Some(callee) = rcvr_expr {
format!("{}; use overloaded call notation instead (e.g., `{}()`)",
msg,
- pprust::expr_to_string(callee))
+ self.tcx.map.node_to_pretty_string(callee.id))
} else {
msg
};
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{self, PatKind};
-use rustc::hir::print as pprust;
use rustc::middle::lang_items;
use rustc_back::slice;
use rustc_const_eval::eval_length;
fn visit_ty(&mut self, t: &'tcx hir::Ty) {
match t.node {
- hir::TyArray(_, ref expr) => {
- check_const_with_type(self.ccx, &expr, self.ccx.tcx.types.usize, expr.id);
+ hir::TyArray(_, length) => {
+ check_const_with_type(self.ccx, length, self.ccx.tcx.types.usize, length.node_id);
}
_ => {}
}
intravisit::walk_ty(self, t);
}
+
+ 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);
+ }
+ _ => {}
+ }
+
+ intravisit::walk_expr(self, e);
+ }
}
impl<'a, 'tcx> ItemLikeVisitor<'tcx> for CheckItemBodiesVisitor<'a, 'tcx> {
check_item_body(self.ccx, i);
}
+ fn visit_trait_item(&mut self, _item: &'tcx hir::TraitItem) {
+ // done as part of `visit_item` above
+ }
+
fn visit_impl_item(&mut self, _item: &'tcx hir::ImplItem) {
// done as part of `visit_item` above
}
fn check_bare_fn<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
decl: &'tcx hir::FnDecl,
- body_id: hir::ExprId,
+ body_id: hir::BodyId,
fn_id: ast::NodeId,
span: Span) {
- let body = ccx.tcx.map.expr(body_id);
+ let body = ccx.tcx.map.body(body_id);
let raw_fty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(fn_id));
let fn_ty = match raw_fty.sty {
ty::TyFnDef(.., f) => f,
- _ => span_bug!(body.span, "check_bare_fn: function type expected")
+ _ => span_bug!(body.value.span, "check_bare_fn: function type expected")
};
check_abi(ccx, span, fn_ty.abi);
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_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.span, body_id.node_id(), &fn_sig);
+ inh.normalize_associated_types_in(body.value.span, body_id.node_id, &fn_sig);
let fcx = check_fn(&inh, fn_ty.unsafety, fn_id, &fn_sig, decl, fn_id, body);
fcx.check_casts();
fcx.select_all_obligations_or_error(); // Casts can introduce new obligations.
- fcx.regionck_fn(fn_id, decl, body_id);
- fcx.resolve_type_vars_in_fn(decl, body, fn_id);
+ fcx.regionck_fn(fn_id, body);
+ fcx.resolve_type_vars_in_body(body, fn_id);
});
}
intravisit::walk_pat(self, p);
}
- fn visit_block(&mut self, b: &'gcx hir::Block) {
- // non-obvious: the `blk` variable maps to region lb, so
- // we have to keep this up-to-date. This
- // is... unfortunate. It'd be nice to not need this.
- intravisit::walk_block(self, b);
- }
-
- // Since an expr occurs as part of the type fixed size arrays we
- // need to record the type for that node
- fn visit_ty(&mut self, t: &'gcx hir::Ty) {
- match t.node {
- hir::TyArray(ref ty, ref count_expr) => {
- self.visit_ty(&ty);
- self.fcx.check_expr_with_hint(&count_expr, self.fcx.tcx.types.usize);
- }
- hir::TyBareFn(ref function_declaration) => {
- intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
- walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
- }
- _ => intravisit::walk_ty(self, t)
- }
- }
-
// Don't descend into the bodies of nested closures
fn visit_fn(&mut self, _: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
- _: hir::ExprId, _: Span, _: ast::NodeId) { }
+ _: hir::BodyId, _: Span, _: ast::NodeId) { }
}
/// Helper used by check_bare_fn and check_expr_fn. Does the grungy work of checking a function
fn_sig: &ty::FnSig<'tcx>,
decl: &'gcx hir::FnDecl,
fn_id: ast::NodeId,
- body: &'gcx hir::Expr)
+ body: &'gcx hir::Body)
-> FnCtxt<'a, 'gcx, 'tcx>
{
let mut fn_sig = fn_sig.clone();
// Create the function context. This is either derived from scratch or,
// in the case of function expressions, based on the outer context.
- let mut fcx = FnCtxt::new(inherited, None, body.id);
+ 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);
fn_sig = fcx.tcx.mk_fn_sig(fn_sig.inputs().iter().cloned(), &fcx.ret_ty.unwrap(),
fn_sig.variadic);
- {
- let mut visit = GatherLocalsVisitor { fcx: &fcx, };
-
- // Add formal parameters.
- for (arg_ty, input) in fn_sig.inputs().iter().zip(&decl.inputs) {
- // The type of the argument must be well-formed.
- //
- // NB -- this is now checked in wfcheck, but that
- // currently only results in warnings, so we issue an
- // old-style WF obligation here so that we still get the
- // errors that we used to get.
- fcx.register_old_wf_obligation(arg_ty, input.ty.span, traits::MiscObligation);
-
- // Create type variables for each argument.
- input.pat.each_binding(|_bm, pat_id, sp, _path| {
- let var_ty = visit.assign(sp, pat_id, None);
- fcx.require_type_is_sized(var_ty, sp, traits::VariableType(pat_id));
- });
+ GatherLocalsVisitor { fcx: &fcx, }.visit_body(body);
- // Check the pattern.
- fcx.check_pat(&input.pat, arg_ty);
- fcx.write_ty(input.id, arg_ty);
- }
+ // Add formal parameters.
+ for (arg_ty, arg) in fn_sig.inputs().iter().zip(&body.arguments) {
+ // The type of the argument must be well-formed.
+ //
+ // NB -- this is now checked in wfcheck, but that
+ // currently only results in warnings, so we issue an
+ // old-style WF obligation here so that we still get the
+ // errors that we used to get.
+ fcx.register_old_wf_obligation(arg_ty, arg.pat.span, traits::MiscObligation);
- visit.visit_expr(body);
+ // Check the pattern.
+ fcx.check_pat(&arg.pat, arg_ty);
+ fcx.write_ty(arg.id, arg_ty);
}
inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig);
- fcx.check_expr_coercable_to_type(body, fcx.ret_ty.unwrap());
+ fcx.check_expr_coercable_to_type(&body.value, fcx.ret_ty.unwrap());
fcx
}
let _indenter = indenter();
match it.node {
// Consts can play a role in type-checking, so they are included here.
- hir::ItemStatic(.., ref e) |
- hir::ItemConst(_, ref e) => check_const(ccx, &e, it.id),
+ hir::ItemStatic(.., e) |
+ hir::ItemConst(_, e) => check_const(ccx, e, it.id),
hir::ItemEnum(ref enum_definition, _) => {
check_enum_variants(ccx,
it.span,
err.emit();
}
- if let hir::ForeignItemFn(ref fn_decl, _) = item.node {
+ if let hir::ForeignItemFn(ref fn_decl, _, _) = item.node {
require_c_abi_if_variadic(ccx.tcx, fn_decl, m.abi, item.span);
}
}
for impl_item_ref in impl_item_refs {
let impl_item = ccx.tcx.map.impl_item(impl_item_ref.id);
match impl_item.node {
- hir::ImplItemKind::Const(_, ref expr) => {
- check_const(ccx, &expr, impl_item.id)
+ hir::ImplItemKind::Const(_, expr) => {
+ check_const(ccx, expr, impl_item.id)
}
hir::ImplItemKind::Method(ref sig, body_id) => {
check_bare_fn(ccx, &sig.decl, body_id, impl_item.id, impl_item.span);
}
}
}
- hir::ItemTrait(.., ref trait_items) => {
- for trait_item in trait_items {
+ hir::ItemTrait(.., ref trait_item_refs) => {
+ for trait_item_ref in trait_item_refs {
+ let trait_item = ccx.tcx.map.trait_item(trait_item_ref.id);
match trait_item.node {
- hir::ConstTraitItem(_, Some(ref expr)) => {
- check_const(ccx, &expr, trait_item.id)
+ hir::TraitItemKind::Const(_, Some(expr)) => {
+ check_const(ccx, expr, trait_item.id)
}
- hir::MethodTraitItem(ref sig, Some(body_id)) => {
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body_id)) => {
check_bare_fn(ccx, &sig.decl, body_id, trait_item.id, trait_item.span);
}
- hir::MethodTraitItem(_, None) |
- hir::ConstTraitItem(_, None) |
- hir::TypeTraitItem(..) => {
+ hir::TraitItemKind::Method(_, hir::TraitMethod::Required(_)) |
+ hir::TraitItemKind::Const(_, None) |
+ hir::TraitItemKind::Type(..) => {
// Nothing to do.
}
}
compare_impl_method(ccx,
&ty_impl_item,
impl_item.span,
- body_id.node_id(),
+ body_id.node_id,
&ty_trait_item,
impl_trait_ref,
trait_span,
compare_impl_method(ccx,
&ty_impl_item,
impl_item.span,
- body_id.node_id(),
+ body_id.node_id,
&ty_trait_item,
impl_trait_ref,
trait_span,
/// Checks a constant with a given type.
fn check_const_with_type<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>,
- expr: &'tcx hir::Expr,
+ body: hir::BodyId,
expected_type: Ty<'tcx>,
id: ast::NodeId) {
+ let body = ccx.tcx.map.body(body);
ccx.inherited(id).enter(|inh| {
- let fcx = FnCtxt::new(&inh, None, expr.id);
- fcx.require_type_is_sized(expected_type, expr.span, traits::ConstSized);
+ 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_expr(expr);
+ GatherLocalsVisitor { fcx: &fcx }.visit_body(body);
- fcx.check_expr_coercable_to_type(expr, expected_type);
+ fcx.check_expr_coercable_to_type(&body.value, expected_type);
fcx.select_all_obligations_and_apply_defaults();
- fcx.closure_analyze(expr);
+ fcx.closure_analyze(body);
fcx.select_obligations_where_possible();
fcx.check_casts();
fcx.select_all_obligations_or_error();
- fcx.regionck_expr(expr);
- fcx.resolve_type_vars_in_expr(expr, id);
+ fcx.regionck_expr(body);
+ fcx.resolve_type_vars_in_body(body, id);
});
}
fn check_const<'a, 'tcx>(ccx: &CrateCtxt<'a,'tcx>,
- expr: &'tcx hir::Expr,
+ body: hir::BodyId,
id: ast::NodeId) {
let decl_ty = ccx.tcx.item_type(ccx.tcx.map.local_def_id(id));
- check_const_with_type(ccx, expr, decl_ty, id);
+ check_const_with_type(ccx, body, decl_ty, id);
}
/// Checks whether a type can be represented in memory. In particular, it
let repr_type_ty = ccx.tcx.enum_repr_type(Some(&hint)).to_ty(ccx.tcx);
for v in vs {
- if let Some(ref e) = v.node.disr_expr {
- check_const_with_type(ccx, e, repr_type_ty, e.id);
+ if let Some(e) = v.node.disr_expr {
+ check_const_with_type(ccx, e, repr_type_ty, e.node_id);
}
}
let variant_i_node_id = ccx.tcx.map.as_local_node_id(variants[i].did).unwrap();
let variant_i = ccx.tcx.map.expect_variant(variant_i_node_id);
let i_span = match variant_i.node.disr_expr {
- Some(ref expr) => expr.span,
+ Some(expr) => ccx.tcx.map.span(expr.node_id),
None => ccx.tcx.map.span(variant_i_node_id)
};
let span = match v.node.disr_expr {
- Some(ref expr) => expr.span,
+ Some(expr) => ccx.tcx.map.span(expr.node_id),
None => v.span
};
struct_span_err!(ccx.tcx.sess, span, E0081,
match self.locals.borrow().get(&nid) {
Some(&t) => t,
None => {
- struct_span_err!(self.tcx.sess, span, E0513,
- "no type for local variable {}",
- self.tcx.map.node_to_string(nid))
- .span_label(span, &"no type for variable")
- .emit();
- self.tcx.types.err
+ span_bug!(span, "no type for local variable {}",
+ self.tcx.map.node_to_string(nid));
}
}
}
debug!("struct named {:?}", base_t);
if let Some(field) = base_def.struct_variant().find_field_named(field.node) {
let field_ty = self.field_ty(expr.span, field, substs);
- if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
+ if self.tcx.vis_is_accessible_from(field.vis, self.body_id) {
autoderef.finalize(lvalue_pref, Some(base));
self.write_autoderef_adjustment(base.id, autoderefs, base_t);
}
ty::TyRawPtr(..) => {
err.note(&format!("`{0}` is a native pointer; perhaps you need to deref with \
- `(*{0}).{1}`", pprust::expr_to_string(base), field.node));
+ `(*{0}).{1}`",
+ self.tcx.map.node_to_pretty_string(base.id),
+ field.node));
}
_ => {}
}
base_def.struct_variant().fields.get(idx.node).and_then(|field| {
let field_ty = self.field_ty(expr.span, field, substs);
private_candidate = Some((base_def.did, field_ty));
- if field.vis.is_accessible_from(self.body_id, &self.tcx().map) {
+ if self.tcx.vis_is_accessible_from(field.vis, self.body_id) {
self.tcx.check_stability(field.did, expr.id, expr.span);
Some(field_ty)
} else {
self.diverges.set(self.diverges.get() | old_diverges);
self.has_errors.set(self.has_errors.get() | old_has_errors);
- debug!("type of expr({}) {} is...", expr.id,
- pprust::expr_to_string(expr));
- debug!("... {:?}, expected is {:?}",
- ty,
- expected);
+ debug!("type of {} is...", self.tcx.map.node_to_string(expr.id));
+ debug!("... {:?}, expected is {:?}", ty, expected);
// Add adjustments to !-expressions
if ty.is_never() {
self.check_method_call(expr, name, args, &tps[..], expected, lvalue_pref)
}
hir::ExprCast(ref e, ref t) => {
- if let hir::TyArray(_, ref count_expr) = t.node {
- self.check_expr_with_hint(&count_expr, tcx.types.usize);
- }
-
// Find the type of `e`. Supply hints based on the type we are casting to,
// if appropriate.
let t_cast = self.to_ty(t);
}
tcx.mk_array(unified, args.len())
}
- hir::ExprRepeat(ref element, ref count_expr) => {
- self.check_expr_has_type(&count_expr, tcx.types.usize);
- let count = eval_length(self.tcx.global_tcx(), &count_expr, "repeat count")
+ hir::ExprRepeat(ref element, count) => {
+ let count_expr = &tcx.map.body(count).value;
+ let count = eval_length(self.tcx.global_tcx(), count_expr, "repeat count")
.unwrap_or(0);
let uty = match expected {
// PUBLIC ENTRY POINTS
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn regionck_expr(&self, e: &'gcx hir::Expr) {
- let mut rcx = RegionCtxt::new(self, RepeatingScope(e.id), e.id, Subject(e.id));
+ pub fn regionck_expr(&self, body: &'gcx hir::Body) {
+ let id = body.value.id;
+ let mut rcx = RegionCtxt::new(self, RepeatingScope(id), id, Subject(id));
if self.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
- rcx.visit_expr(e);
- rcx.visit_region_obligations(e.id);
+ rcx.visit_body(body);
+ rcx.visit_region_obligations(id);
}
rcx.resolve_regions_and_report_errors();
}
pub fn regionck_fn(&self,
fn_id: ast::NodeId,
- decl: &hir::FnDecl,
- body_id: hir::ExprId) {
+ body: &'gcx hir::Body) {
debug!("regionck_fn(id={})", fn_id);
- let node_id = body_id.node_id();
+ let node_id = body.value.id;
let mut rcx = RegionCtxt::new(self, RepeatingScope(node_id), node_id, Subject(fn_id));
if self.err_count_since_creation() == 0 {
// regionck assumes typeck succeeded
- rcx.visit_fn_body(fn_id, decl, body_id, self.tcx.map.span(fn_id));
+ rcx.visit_fn_body(fn_id, body, self.tcx.map.span(fn_id));
}
rcx.free_region_map.relate_free_regions_from_predicates(
fn visit_fn_body(&mut self,
id: ast::NodeId, // the id of the fn itself
- fn_decl: &hir::FnDecl,
- body_id: hir::ExprId,
+ body: &'gcx hir::Body,
span: Span)
{
// When we enter a function, we can derive
debug!("visit_fn_body(id={})", id);
+ let body_id = body.id();
+
let call_site = self.tcx.region_maps.lookup_code_extent(
- region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id() });
+ region::CodeExtentData::CallSiteScope { fn_id: id, body_id: body_id.node_id });
let old_call_site_scope = self.set_call_site_scope(Some(call_site));
let fn_sig = {
let fn_sig_tys: Vec<_> =
fn_sig.inputs().iter().cloned().chain(Some(fn_sig.output())).collect();
- let old_body_id = self.set_body_id(body_id.node_id());
- self.relate_free_regions(&fn_sig_tys[..], body_id.node_id(), span);
- self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id()),
- &fn_decl.inputs[..]);
- let body = self.tcx.map.expr(body_id);
- self.visit_expr(body);
- self.visit_region_obligations(body_id.node_id());
+ let old_body_id = self.set_body_id(body_id.node_id);
+ self.relate_free_regions(&fn_sig_tys[..], body_id.node_id, span);
+ self.link_fn_args(self.tcx.region_maps.node_extent(body_id.node_id), &body.arguments);
+ self.visit_body(body);
+ self.visit_region_obligations(body_id.node_id);
let call_site_scope = self.call_site_scope.unwrap();
- debug!("visit_fn_body body.id {} call_site_scope: {:?}",
- body.id, call_site_scope);
+ debug!("visit_fn_body body.id {:?} call_site_scope: {:?}",
+ body.id(), call_site_scope);
let call_site_region = self.tcx.mk_region(ty::ReScope(call_site_scope));
self.type_of_node_must_outlive(infer::CallReturn(span),
- body_id.node_id(),
+ body_id.node_id,
call_site_region);
self.region_bound_pairs.truncate(old_region_bounds_pairs_len);
// regions, until regionck, as described in #3238.
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
- NestedVisitorMap::OnlyBodies(&self.tcx.map)
+ NestedVisitorMap::None
}
- fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, fd: &'gcx hir::FnDecl,
- b: hir::ExprId, span: Span, id: ast::NodeId) {
- self.visit_fn_body(id, fd, b, span)
+ fn visit_fn(&mut self, _fk: intravisit::FnKind<'gcx>, _: &'gcx hir::FnDecl,
+ b: hir::BodyId, span: Span, id: ast::NodeId) {
+ let body = self.tcx.map.body(b);
+ self.visit_fn_body(id, body, span)
}
//visit_pat: visit_pat, // (..) see above
fn check_expr_fn_block(&mut self,
expr: &'gcx hir::Expr,
- body_id: hir::ExprId) {
- let repeating_scope = self.set_repeating_scope(body_id.node_id());
+ body_id: hir::BodyId) {
+ let repeating_scope = self.set_repeating_scope(body_id.node_id);
intravisit::walk_expr(self, expr);
self.set_repeating_scope(repeating_scope);
}
for arg in args {
let arg_ty = self.node_ty(arg.id);
let re_scope = self.tcx.mk_region(ty::ReScope(body_scope));
- let arg_cmt = mc.cat_rvalue(arg.id, arg.ty.span, re_scope, arg_ty);
+ let arg_cmt = mc.cat_rvalue(arg.id, arg.pat.span, re_scope, arg_ty);
debug!("arg_ty={:?} arg_cmt={:?} arg={:?}",
arg_ty,
arg_cmt,
// PUBLIC ENTRY POINTS
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn closure_analyze(&self, body: &'gcx hir::Expr) {
+ pub fn closure_analyze(&self, body: &'gcx hir::Body) {
let mut seed = SeedBorrowKind::new(self);
- seed.visit_expr(body);
+ seed.visit_body(body);
let mut adjust = AdjustBorrowKind::new(self, seed.temp_closure_kinds);
- adjust.visit_expr(body);
+ adjust.visit_body(body);
// it's our job to process these.
assert!(self.deferred_call_resolutions.borrow().is_empty());
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for SeedBorrowKind<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
- NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+ NestedVisitorMap::None
}
fn visit_expr(&mut self, expr: &'gcx hir::Expr) {
match expr.node {
hir::ExprClosure(cc, _, body_id, _) => {
- self.check_closure(expr, cc, body_id);
+ let body = self.fcx.tcx.map.body(body_id);
+ self.visit_body(body);
+ self.check_closure(expr, cc);
}
_ => { }
fn check_closure(&mut self,
expr: &hir::Expr,
- capture_clause: hir::CaptureClause,
- _body_id: hir::ExprId)
+ capture_clause: hir::CaptureClause)
{
let closure_def_id = self.fcx.tcx.map.local_def_id(expr.id);
if !self.fcx.tables.borrow().closure_kinds.contains_key(&closure_def_id) {
fn analyze_closure(&mut self,
id: ast::NodeId,
span: Span,
- decl: &hir::FnDecl,
- body_id: hir::ExprId) {
+ body: &hir::Body) {
/*!
* Analysis starting point.
*/
- debug!("analyze_closure(id={:?}, body.id={:?})", id, body_id);
+ debug!("analyze_closure(id={:?}, body.id={:?})", id, body.id());
{
- let body = self.fcx.tcx.map.expr(body_id);
let mut euv =
euv::ExprUseVisitor::with_options(self,
self.fcx,
mc::MemCategorizationOptions {
during_closure_kind_inference: true
});
- euv.walk_fn(decl, body);
+ euv.consume_body(body);
}
// Now that we've analyzed the closure, we know how each
impl<'a, 'gcx, 'tcx> Visitor<'gcx> for AdjustBorrowKind<'a, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
- NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+ NestedVisitorMap::None
}
fn visit_fn(&mut self,
fn_kind: intravisit::FnKind<'gcx>,
decl: &'gcx hir::FnDecl,
- body: hir::ExprId,
+ body: hir::BodyId,
span: Span,
id: ast::NodeId)
{
intravisit::walk_fn(self, fn_kind, decl, body, span, id);
- self.analyze_closure(id, span, decl, body);
+
+ let body = self.fcx.tcx.map.body(body);
+ self.visit_body(body);
+ self.analyze_closure(id, span, body);
}
}
}
}
- fn check_trait_or_impl_item(&mut self,
- item_id: ast::NodeId,
- span: Span,
- sig_if_method: Option<&hir::MethodSig>) {
+ fn check_associated_item(&mut self,
+ item_id: ast::NodeId,
+ span: Span,
+ sig_if_method: Option<&hir::MethodSig>) {
let code = self.code.clone();
self.for_id(item_id, span).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
fn check_item_fn(&mut self,
item: &hir::Item,
- body_id: hir::ExprId)
+ body_id: hir::BodyId)
{
self.for_item(item).with_fcx(|fcx, this| {
let free_substs = &fcx.parameter_environment.free_substs;
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());
+ 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,
free_id_outlive, &mut implied_bounds);
implied_bounds
return;
}
- let span = method_sig.decl.inputs[0].pat.span;
+ let span = method_sig.decl.inputs[0].span;
let free_substs = &fcx.parameter_environment.free_substs;
let method_ty = fcx.tcx.item_type(method.def_id);
fn visit_trait_item(&mut self, trait_item: &'v hir::TraitItem) {
debug!("visit_trait_item: {:?}", trait_item);
let method_sig = match trait_item.node {
- hir::TraitItem_::MethodTraitItem(ref sig, _) => Some(sig),
+ hir::TraitItemKind::Method(ref sig, _) => Some(sig),
_ => None
};
- self.check_trait_or_impl_item(trait_item.id, trait_item.span, method_sig);
+ self.check_associated_item(trait_item.id, trait_item.span, method_sig);
intravisit::walk_trait_item(self, trait_item)
}
hir::ImplItemKind::Method(ref sig, _) => Some(sig),
_ => None
};
- self.check_trait_or_impl_item(impl_item.id, impl_item.span, method_sig);
+ self.check_associated_item(impl_item.id, impl_item.span, method_sig);
intravisit::walk_impl_item(self, impl_item)
}
}
use syntax::ast;
use syntax_pos::Span;
-use rustc::hir::print::pat_to_string;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
-use rustc::hir::{self, PatKind};
+use rustc::hir;
///////////////////////////////////////////////////////////////////////////
-// Entry point functions
+// Entry point
impl<'a, 'gcx, 'tcx> FnCtxt<'a, 'gcx, 'tcx> {
- pub fn resolve_type_vars_in_expr(&self, e: &'gcx hir::Expr, item_id: ast::NodeId) {
+ pub fn resolve_type_vars_in_body(&self,
+ body: &'gcx hir::Body,
+ item_id: ast::NodeId) {
assert_eq!(self.writeback_errors.get(), false);
let mut wbcx = WritebackCx::new(self);
- wbcx.visit_expr(e);
- wbcx.visit_upvar_borrow_map();
- wbcx.visit_closures();
- wbcx.visit_liberated_fn_sigs();
- wbcx.visit_fru_field_types();
- wbcx.visit_deferred_obligations(item_id);
- wbcx.visit_type_nodes();
- }
-
- pub fn resolve_type_vars_in_fn(&self,
- decl: &'gcx hir::FnDecl,
- body: &'gcx hir::Expr,
- item_id: ast::NodeId) {
- assert_eq!(self.writeback_errors.get(), false);
- let mut wbcx = WritebackCx::new(self);
- wbcx.visit_expr(body);
- for arg in &decl.inputs {
+ for arg in &body.arguments {
wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.id);
- wbcx.visit_pat(&arg.pat);
-
- // Privacy needs the type for the whole pattern, not just each binding
- if let PatKind::Binding(..) = arg.pat.node {} else {
- wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.pat.id);
- }
}
+ wbcx.visit_body(body);
wbcx.visit_upvar_borrow_map();
wbcx.visit_closures();
wbcx.visit_liberated_fn_sigs();
impl<'cx, 'gcx, 'tcx> Visitor<'gcx> for WritebackCx<'cx, 'gcx, 'tcx> {
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'gcx> {
- NestedVisitorMap::OnlyBodies(&self.fcx.tcx.map)
+ NestedVisitorMap::None
}
fn visit_stmt(&mut self, s: &'gcx hir::Stmt) {
self.visit_method_map_entry(ResolvingExpr(e.span),
MethodCall::expr(e.id));
- if let hir::ExprClosure(_, ref decl, ..) = e.node {
- for input in &decl.inputs {
- self.visit_node_id(ResolvingExpr(e.span), input.id);
+ if let hir::ExprClosure(_, _, body, _) = e.node {
+ let body = self.fcx.tcx.map.body(body);
+ for arg in &body.arguments {
+ self.visit_node_id(ResolvingExpr(e.span), arg.id);
}
+
+ self.visit_body(body);
}
intravisit::walk_expr(self, e);
self.visit_node_id(ResolvingPattern(p.span), p.id);
debug!("Type for pattern binding {} (id {}) resolved to {:?}",
- pat_to_string(p),
+ self.tcx().map.node_to_pretty_string(p.id),
p.id,
self.tcx().tables().node_id_to_type(p.id));
self.write_ty_to_tcx(l.id, var_ty);
intravisit::walk_local(self, l);
}
-
- fn visit_ty(&mut self, t: &'gcx hir::Ty) {
- match t.node {
- hir::TyArray(ref ty, ref count_expr) => {
- self.visit_ty(&ty);
- self.write_ty_to_tcx(count_expr.id, self.tcx().types.usize);
- }
- hir::TyBareFn(ref function_declaration) => {
- intravisit::walk_fn_decl_nopat(self, &function_declaration.decl);
- walk_list!(self, visit_lifetime_def, &function_declaration.lifetimes);
- }
- _ => intravisit::walk_ty(self, t)
- }
- }
}
impl<'cx, 'gcx, 'tcx> WritebackCx<'cx, 'gcx, 'tcx> {
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
}
+}
+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
/// apply to a specific impl, so just return after reporting one
/// to prevent inundating the user with a bunch of similar error
/// reports.
- fn check_item(&self, item: &hir::Item) {
+ fn visit_item(&mut self, item: &hir::Item) {
let def_id = self.tcx.map.local_def_id(item.id);
match item.node {
hir::ItemImpl(.., None, ref ty, _) => {
the crate they're defined in; define a new trait instead")
.span_label(item_trait_ref.path.span,
&format!("`{}` trait not defined in this crate",
- item_trait_ref.path))
+ self.tcx.map.node_to_pretty_string(item_trait_ref.ref_id)))
.emit();
return;
}
}
}
}
-}
-impl<'cx, 'tcx, 'v> ItemLikeVisitor<'v> for OrphanChecker<'cx, 'tcx> {
- fn visit_item(&mut self, item: &hir::Item) {
- self.check_item(item);
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
}
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
use syntax::symbol::{Symbol, keywords};
use syntax_pos::Span;
-use rustc::hir::{self, map as hir_map, print as pprust};
+use rustc::hir::{self, map as hir_map};
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
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)
+ });
+ 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)
id: ast::NodeId,
sig: &hir::MethodSig,
untransformed_rcvr_ty: Ty<'tcx>,
- rcvr_ty_predicates: &ty::GenericPredicates<'tcx>) {
+ body: Option<hir::BodyId>,
+ rcvr_ty_predicates: &ty::GenericPredicates<'tcx>,) {
let def_id = ccx.tcx.map.local_def_id(id);
let ty_generics = generics_of_def_id(ccx, def_id);
ImplContainer(_) => Some(AnonTypeScope::new(def_id)),
TraitContainer(_) => None
};
+ let assoc_item = ccx.tcx.associated_item(def_id);
+ let self_value_ty = if assoc_item.method_has_self_argument {
+ Some(untransformed_rcvr_ty)
+ } else {
+ None
+ };
let fty = AstConv::ty_of_method(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
- sig, untransformed_rcvr_ty, anon_scope);
+ sig, self_value_ty, body, anon_scope);
let substs = mk_item_substs(&ccx.icx(&(rcvr_ty_predicates, &sig.generics)),
ccx.tcx.map.span(id), def_id);
tcx.predicates.borrow_mut().insert(def_id, ty_predicates.clone());
},
- hir::ItemTrait(.., ref trait_items) => {
+ 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);
- let trait_predicates = tcx.item_predicates(def_id);
-
- debug!("convert: trait_bounds={:?}", trait_predicates);
-
- // FIXME: is the ordering here important? I think it is.
- let container = TraitContainer(def_id);
-
- // Convert all the associated constants.
- for trait_item in trait_items {
- if let hir::ConstTraitItem(ref ty, _) = trait_item.node {
- let const_def_id = ccx.tcx.map.local_def_id(trait_item.id);
- generics_of_def_id(ccx, const_def_id);
- let ty = ccx.icx(&trait_predicates)
- .to_ty(&ExplicitRscope, ty);
- tcx.item_types.borrow_mut().insert(const_def_id, ty);
- convert_associated_const(ccx, container, trait_item.id, ty)
- }
- }
-
- // Convert all the associated types.
- for trait_item in trait_items {
- if let hir::TypeTraitItem(_, ref opt_ty) = trait_item.node {
- let type_def_id = ccx.tcx.map.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(&ExplicitRscope, &ty)
- });
-
- convert_associated_type(ccx, container, trait_item.id, typ);
- }
- }
-
- // Convert all the methods
- for trait_item in trait_items {
- if let hir::MethodTraitItem(ref sig, _) = trait_item.node {
- convert_method(ccx,
- container,
- trait_item.id,
- sig,
- tcx.mk_self_type(),
- &trait_predicates);
- }
- }
},
hir::ItemStruct(ref struct_def, _) |
hir::ItemUnion(ref struct_def, _) => {
}
}
+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.map.get_parent_did(trait_item.id);
+ let trait_predicates = tcx.item_predicates(trait_def_id);
+
+ match trait_item.node {
+ hir::TraitItemKind::Const(ref ty, _) => {
+ let const_def_id = ccx.tcx.map.local_def_id(trait_item.id);
+ generics_of_def_id(ccx, const_def_id);
+ let ty = ccx.icx(&trait_predicates)
+ .to_ty(&ExplicitRscope, &ty);
+ tcx.item_types.borrow_mut().insert(const_def_id, ty);
+ convert_associated_const(ccx, TraitContainer(trait_def_id),
+ trait_item.id, ty);
+ }
+
+ hir::TraitItemKind::Type(_, ref opt_ty) => {
+ let type_def_id = ccx.tcx.map.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(&ExplicitRscope, &ty)
+ });
+
+ convert_associated_type(ccx, TraitContainer(trait_def_id), trait_item.id, typ);
+ }
+
+ hir::TraitItemKind::Method(ref sig, ref method) => {
+ let body = match *method {
+ hir::TraitMethod::Required(_) => None,
+ hir::TraitMethod::Provided(body) => Some(body)
+ };
+ convert_method(ccx, TraitContainer(trait_def_id),
+ trait_item.id, sig, tcx.mk_self_type(),
+ body, &trait_predicates);
+ }
+ }
+}
+
fn convert_impl_item(ccx: &CrateCtxt, impl_item: &hir::ImplItem) {
let tcx = ccx.tcx;
convert_associated_type(ccx, ImplContainer(impl_def_id), impl_item.id, Some(typ));
}
- hir::ImplItemKind::Method(ref sig, _) => {
+ hir::ImplItemKind::Method(ref sig, body) => {
convert_method(ccx, ImplContainer(impl_def_id),
impl_item.id, sig, impl_self_ty,
- &impl_predicates);
+ Some(body), &impl_predicates);
}
}
}
fn evaluate_disr_expr(ccx: &CrateCtxt, repr_ty: attr::IntType, e: &hir::Expr)
-> Option<ty::Disr> {
- debug!("disr expr, checking {}", pprust::expr_to_string(e));
+ debug!("disr expr, checking {}", ccx.tcx.map.node_to_pretty_string(e.id));
let ty_hint = repr_ty.to_ty(ccx.tcx);
let print_err = |cv: ConstVal| {
let mut prev_disr = None::<ty::Disr>;
let variants = def.variants.iter().map(|v| {
let wrapped_disr = prev_disr.map_or(initial, |d| d.wrap_incr());
- let disr = if let Some(ref e) = v.node.disr_expr {
+ let disr = if let Some(e) = v.node.disr_expr {
+ let e = &tcx.map.body(e).value;
evaluate_disr_expr(ccx, repr_type, e)
} else if let Some(disr) = repr_type.disr_incr(tcx, prev_disr) {
Some(disr)
ast_generics: &hir::Generics,
trait_predicates: &ty::GenericPredicates<'tcx>,
self_trait_ref: ty::TraitRef<'tcx>,
- trait_items: &[hir::TraitItem])
+ trait_item_refs: &[hir::TraitItemRef])
-> Vec<ty::Predicate<'tcx>>
{
- trait_items.iter().flat_map(|trait_item| {
+ trait_item_refs.iter().flat_map(|trait_item_ref| {
+ let trait_item = ccx.tcx.map.trait_item(trait_item_ref.id);
let bounds = match trait_item.node {
- hir::TypeTraitItem(ref bounds, _) => bounds,
+ hir::TraitItemKind::Type(ref bounds, _) => bounds,
_ => {
return vec![].into_iter();
}
let ast_generics = match node {
NodeTraitItem(item) => {
match item.node {
- MethodTraitItem(ref sig, _) => &sig.generics,
+ TraitItemKind::Method(ref sig, _) => &sig.generics,
_ => &no_generics
}
}
NodeForeignItem(item) => {
match item.node {
ForeignItemStatic(..) => &no_generics,
- ForeignItemFn(_, ref generics) => generics
+ ForeignItemFn(_, _, ref generics) => generics
}
}
ItemStatic(ref t, ..) | ItemConst(ref t, _) => {
ccx.icx(&()).to_ty(&StaticRscope::new(&ccx.tcx), &t)
}
- ItemFn(ref decl, unsafety, _, abi, ref generics, _) => {
+ ItemFn(ref decl, unsafety, _, abi, ref generics, body) => {
let tofd = AstConv::ty_of_bare_fn(&ccx.icx(generics), unsafety, abi, &decl,
- Some(AnonTypeScope::new(def_id)));
+ body, Some(AnonTypeScope::new(def_id)));
let substs = mk_item_substs(&ccx.icx(generics), item.span, def_id);
ccx.tcx.mk_fn_def(def_id, substs, tofd)
}
let abi = ccx.tcx.map.get_foreign_abi(node_id);
match foreign_item.node {
- ForeignItemFn(ref fn_decl, ref generics) => {
+ ForeignItemFn(ref fn_decl, _, ref generics) => {
compute_type_of_foreign_fn_decl(
ccx, ccx.tcx.map.local_def_id(foreign_item.id),
fn_decl, generics, abi)
let no_generics = hir::Generics::empty();
let generics = match it.node {
- hir::ForeignItemFn(_, ref generics) => generics,
+ hir::ForeignItemFn(_, _, ref generics) => generics,
hir::ForeignItemStatic(..) => &no_generics
};
ccx.tcx.sess.struct_span_err(ast_ty.span,
&format!("use of SIMD type `{}` in FFI is highly experimental and \
may result in invalid code",
- pprust::ty_to_string(ast_ty)))
+ ccx.tcx.map.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(&input_tys) {
- check(&input.ty, ty)
+ check(&input, ty)
}
if let hir::Return(ref ty) = decl.output {
check(&ty, output)
You have two possibilities to solve this situation:
- * Give an explicit definition of the expression
- * Infer the expression
+* Give an explicit definition of the expression
+* Infer the expression
Examples:
```
"##,
-E0248: r##"
-This error indicates an attempt to use a value where a type is expected. For
-example:
-
-```compile_fail,E0248
-enum Foo {
- Bar(u32)
-}
-
-fn do_something(x: Foo::Bar) { }
-```
-
-In this example, we're attempting to take a type of `Foo::Bar` in the
-do_something function. This is not legal: `Foo::Bar` is a value of type `Foo`,
-not a distinct static type. Likewise, it's not legal to attempt to
-`impl Foo::Bar`: instead, you must `impl Foo` and then pattern match to specify
-behavior for specific enum variants.
-"##,
-
E0569: r##"
If an impl has a generic parameter with the `#[may_dangle]` attribute, then
that impl must be declared as an `unsafe impl. For example:
```
"##,
-E0513: r##"
-The type of the variable couldn't be found out.
-
-Erroneous code example:
-
-```compile_fail,E0513
-use std::mem;
-
-unsafe {
- let size = mem::size_of::<u32>();
- mem::transmute_copy::<u32, [u8; size]>(&8_8);
- // error: no type for local variable
-}
-```
-
-To fix this error, please use a constant size instead of `size`. To make
-this error more obvious, you could run:
-
-```compile_fail,E0080
-use std::mem;
-
-unsafe {
- mem::transmute_copy::<u32, [u8; mem::size_of::<u32>()]>(&8_8);
- // error: constant evaluation error
-}
-```
-
-So now, you can fix your code by setting the size directly:
-
-```
-use std::mem;
-
-unsafe {
- mem::transmute_copy::<u32, [u8; 4]>(&8_8);
- // `u32` is 4 bytes so we replace the `mem::size_of` call with its size
-}
-```
-"##,
-
E0516: r##"
The `typeof` keyword is currently reserved but unimplemented.
Erroneous code example:
E0245, // not a trait
// E0246, // invalid recursive type
// E0247,
+// E0248, // value used as a type, now reported earlier during resolution as E0412
// E0249,
// E0319, // trait impls for defaulted traits allowed just for structs/enums
E0320, // recursive overflow during dropck
}
}
+ fn visit_trait_item(&mut self, _trait_item: &'tcx hir::TraitItem) { }
+
fn visit_impl_item(&mut self, _impl_item: &'tcx hir::ImplItem) { }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use rustc::hir;
use rustc::hir::def_id::DefId;
use rustc::ty;
use rustc::ty::subst::Substs;
#[derive(Clone)]
pub struct ElisionFailureInfo {
- pub name: String,
+ /// Where we can find the argument pattern.
+ pub parent: Option<hir::BodyId>,
+ /// The index of the argument in the original definition.
+ pub index: usize,
pub lifetime_count: usize,
pub have_bound_regions: bool
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
}
}
+ fn visit_trait_item(&mut self, _trait_item: &hir::TraitItem) {
+ }
+
fn visit_impl_item(&mut self, _impl_item: &hir::ImplItem) {
}
}
//! Support for inlining external documentation into the current AST.
+use std::collections::BTreeMap;
+use std::io;
use std::iter::once;
use syntax::ast;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::DefId;
-use rustc::hir::print as pprust;
use rustc::ty;
use rustc::util::nodemap::FxHashSet;
-use rustc_const_eval::lookup_const_by_id;
-
use core::{DocContext, DocAccessLevels};
use doctree;
use clean::{self, GetDefId};
match item.kind {
ty::AssociatedKind::Const => {
let default = if item.defaultness.has_value() {
- Some(pprust::expr_to_string(
- lookup_const_by_id(tcx, item.def_id, None).unwrap().0))
+ Some(print_inlined_const(cx, item.def_id))
} else {
None
};
}
}
-fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
- let (expr, ty) = lookup_const_by_id(cx.tcx, did, None).unwrap_or_else(|| {
- panic!("expected lookup_const_by_id to succeed for {:?}", did);
- });
- debug!("converting constant expr {:?} to snippet", expr);
- let sn = pprust::expr_to_string(expr);
- debug!("got snippet {}", sn);
+struct InlinedConst {
+ nested_bodies: BTreeMap<hir::BodyId, hir::Body>
+}
+
+impl hir::print::PpAnn for InlinedConst {
+ fn nested(&self, state: &mut hir::print::State, nested: hir::print::Nested)
+ -> io::Result<()> {
+ if let hir::print::Nested::Body(body) = nested {
+ state.print_expr(&self.nested_bodies[&body].value)
+ } else {
+ Ok(())
+ }
+ }
+}
+fn print_inlined_const(cx: &DocContext, did: DefId) -> String {
+ let body = cx.tcx.sess.cstore.maybe_get_item_body(cx.tcx, did).unwrap();
+ let inlined = InlinedConst {
+ nested_bodies: cx.tcx.sess.cstore.item_body_nested_bodies(did)
+ };
+ hir::print::to_string(&inlined, |s| s.print_expr(&body.value))
+}
+
+fn build_const(cx: &DocContext, did: DefId) -> clean::Constant {
clean::Constant {
- type_: ty.map(|t| t.clean(cx)).unwrap_or_else(|| cx.tcx.item_type(did).clean(cx)),
- expr: sn
+ type_: cx.tcx.item_type(did).clean(cx),
+ expr: print_inlined_const(cx, did)
}
}
use rustc::middle::lang_items;
use rustc::hir::def::{Def, CtorKind};
use rustc::hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE};
-use rustc::hir::print as pprust;
use rustc::ty::subst::Substs;
use rustc::ty::{self, AdtKind};
use rustc::middle::stability;
pub abi: Abi,
}
-impl Clean<Method> for hir::MethodSig {
+impl<'a> Clean<Method> for (&'a hir::MethodSig, hir::BodyId) {
fn clean(&self, cx: &DocContext) -> Method {
- let decl = FnDecl {
- inputs: Arguments {
- values: self.decl.inputs.clean(cx),
- },
- output: self.decl.output.clean(cx),
- variadic: false,
- attrs: Attributes::default()
- };
Method {
- generics: self.generics.clean(cx),
- unsafety: self.unsafety,
- constness: self.constness,
- decl: decl,
- abi: self.abi
+ generics: self.0.generics.clean(cx),
+ unsafety: self.0.unsafety,
+ constness: self.0.constness,
+ decl: (&*self.0.decl, self.1).clean(cx),
+ abi: self.0.abi
}
}
}
pub abi: Abi,
}
-impl Clean<TyMethod> for hir::MethodSig {
- fn clean(&self, cx: &DocContext) -> TyMethod {
- let decl = FnDecl {
- inputs: Arguments {
- values: self.decl.inputs.clean(cx),
- },
- output: self.decl.output.clean(cx),
- variadic: false,
- attrs: Attributes::default()
- };
- TyMethod {
- unsafety: self.unsafety.clone(),
- decl: decl,
- generics: self.generics.clean(cx),
- abi: self.abi
- }
- }
-}
-
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Function {
pub decl: FnDecl,
deprecation: self.depr.clean(cx),
def_id: cx.tcx.map.local_def_id(self.id),
inner: FunctionItem(Function {
- decl: self.decl.clean(cx),
+ decl: (&self.decl, self.body).clean(cx),
generics: self.generics.clean(cx),
unsafety: self.unsafety,
constness: self.constness,
pub values: Vec<Argument>,
}
-impl Clean<FnDecl> for hir::FnDecl {
+impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], &'a [Spanned<ast::Name>]) {
+ fn clean(&self, cx: &DocContext) -> Arguments {
+ Arguments {
+ values: self.0.iter().enumerate().map(|(i, ty)| {
+ let mut name = self.1.get(i).map(|n| n.node.to_string())
+ .unwrap_or(String::new());
+ if name.is_empty() {
+ name = "_".to_string();
+ }
+ Argument {
+ name: name,
+ type_: ty.clean(cx),
+ }
+ }).collect()
+ }
+ }
+}
+
+impl<'a> Clean<Arguments> for (&'a [P<hir::Ty>], hir::BodyId) {
+ fn clean(&self, cx: &DocContext) -> Arguments {
+ let body = cx.tcx.map.body(self.1);
+
+ Arguments {
+ values: self.0.iter().enumerate().map(|(i, ty)| {
+ Argument {
+ name: name_from_pat(&body.arguments[i].pat),
+ type_: ty.clean(cx),
+ }
+ }).collect()
+ }
+ }
+}
+
+impl<'a, A: Copy> Clean<FnDecl> for (&'a hir::FnDecl, A)
+ where (&'a [P<hir::Ty>], A): Clean<Arguments>
+{
fn clean(&self, cx: &DocContext) -> FnDecl {
FnDecl {
- inputs: Arguments {
- values: self.inputs.clean(cx),
- },
- output: self.output.clean(cx),
- variadic: self.variadic,
+ inputs: (&self.0.inputs[..], self.1).clean(cx),
+ output: self.0.output.clean(cx),
+ variadic: self.0.variadic,
attrs: Attributes::default()
}
}
values: sig.skip_binder().inputs().iter().map(|t| {
Argument {
type_: t.clean(cx),
- id: ast::CRATE_NODE_ID,
name: names.next().map_or("".to_string(), |name| name.to_string()),
}
}).collect(),
pub struct Argument {
pub type_: Type,
pub name: String,
- pub id: ast::NodeId,
}
#[derive(Clone, RustcEncodable, RustcDecodable, PartialEq, Debug)]
impl Argument {
pub fn to_self(&self) -> Option<SelfTy> {
- if self.name == "self" {
- match self.type_ {
- Infer => Some(SelfValue),
- BorrowedRef{ref lifetime, mutability, ref type_} if **type_ == Infer => {
- Some(SelfBorrowed(lifetime.clone(), mutability))
- }
- _ => Some(SelfExplicit(self.type_.clone()))
- }
- } else {
- None
+ if self.name != "self" {
+ return None;
}
- }
-}
-
-impl Clean<Argument> for hir::Arg {
- fn clean(&self, cx: &DocContext) -> Argument {
- Argument {
- name: name_from_pat(&*self.pat),
- type_: (self.ty.clean(cx)),
- id: self.id
+ if self.type_.is_self_type() {
+ return Some(SelfValue);
+ }
+ match self.type_ {
+ BorrowedRef{ref lifetime, mutability, ref type_} if type_.is_self_type() => {
+ Some(SelfBorrowed(lifetime.clone(), mutability))
+ }
+ _ => Some(SelfExplicit(self.type_.clone()))
}
}
}
impl Clean<Item> for hir::TraitItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
- hir::ConstTraitItem(ref ty, ref default) => {
+ hir::TraitItemKind::Const(ref ty, default) => {
AssociatedConstItem(ty.clean(cx),
- default.as_ref().map(|e| pprust::expr_to_string(&e)))
+ default.map(|e| print_const_expr(cx, e)))
}
- hir::MethodTraitItem(ref sig, Some(_)) => {
- MethodItem(sig.clean(cx))
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Provided(body)) => {
+ MethodItem((sig, body).clean(cx))
}
- hir::MethodTraitItem(ref sig, None) => {
- TyMethodItem(sig.clean(cx))
+ hir::TraitItemKind::Method(ref sig, hir::TraitMethod::Required(ref names)) => {
+ TyMethodItem(TyMethod {
+ unsafety: sig.unsafety.clone(),
+ decl: (&*sig.decl, &names[..]).clean(cx),
+ generics: sig.generics.clean(cx),
+ abi: sig.abi
+ })
}
- hir::TypeTraitItem(ref bounds, ref default) => {
+ hir::TraitItemKind::Type(ref bounds, ref default) => {
AssociatedTypeItem(bounds.clean(cx), default.clean(cx))
}
};
impl Clean<Item> for hir::ImplItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
- hir::ImplItemKind::Const(ref ty, ref expr) => {
+ hir::ImplItemKind::Const(ref ty, expr) => {
AssociatedConstItem(ty.clean(cx),
- Some(pprust::expr_to_string(expr)))
+ Some(print_const_expr(cx, expr)))
}
- hir::ImplItemKind::Method(ref sig, _) => {
- MethodItem(sig.clean(cx))
+ hir::ImplItemKind::Method(ref sig, body) => {
+ MethodItem((sig, body).clean(cx))
}
hir::ImplItemKind::Type(ref ty) => TypedefItem(Typedef {
type_: ty.clean(cx),
};
let self_arg_ty = *fty.sig.input(0).skip_binder();
if self_arg_ty == self_ty {
- decl.inputs.values[0].type_ = Infer;
+ decl.inputs.values[0].type_ = Generic(String::from("Self"));
} else if let ty::TyRef(_, mt) = self_arg_ty.sty {
if mt.ty == self_ty {
match decl.inputs.values[0].type_ {
- BorrowedRef{ref mut type_, ..} => **type_ = Infer,
+ BorrowedRef{ref mut type_, ..} => {
+ **type_ = Generic(String::from("Self"))
+ }
_ => unreachable!(),
}
}
_ => false,
}
}
+
+ pub fn is_self_type(&self) -> bool {
+ match *self {
+ Generic(ref name) => name == "Self",
+ _ => false
+ }
+ }
}
impl GetDefId for Type {
BorrowedRef {lifetime: l.clean(cx), mutability: m.mutbl.clean(cx),
type_: box m.ty.clean(cx)},
TySlice(ref ty) => Vector(box ty.clean(cx)),
- TyArray(ref ty, ref e) => {
+ TyArray(ref ty, e) => {
use rustc_const_math::{ConstInt, ConstUsize};
use rustc_const_eval::eval_const_expr;
use rustc::middle::const_val::ConstVal;
+ let e = &cx.tcx.map.body(e).value;
let n = match eval_const_expr(cx.tcx, e) {
ConstVal::Integral(ConstInt::Usize(u)) => match u {
ConstUsize::Us16(u) => u.to_string(),
segments.pop();
let trait_path = hir::Path {
span: p.span,
- global: p.global,
def: Def::Trait(cx.tcx.associated_item(p.def.def_id()).container.id()),
segments: segments.into(),
};
}
let trait_path = hir::Path {
span: self.span,
- global: false,
def: def,
segments: vec![].into(),
};
impl Clean<Path> for hir::Path {
fn clean(&self, cx: &DocContext) -> Path {
Path {
- global: self.global,
+ global: self.is_global(),
def: self.def,
- segments: self.segments.clean(cx),
+ segments: if self.is_global() { &self.segments[1..] } else { &self.segments }.clean(cx),
}
}
}
}
fn qpath_to_string(p: &hir::QPath) -> String {
- let (segments, global) = match *p {
- hir::QPath::Resolved(_, ref path) => {
- (&path.segments, path.global)
- }
- hir::QPath::TypeRelative(_, ref segment) => {
- return segment.name.to_string()
- }
+ let segments = match *p {
+ hir::QPath::Resolved(_, ref path) => &path.segments,
+ hir::QPath::TypeRelative(_, ref segment) => return segment.name.to_string(),
};
let mut s = String::new();
- let mut first = true;
- for i in segments.iter().map(|x| x.name.as_str()) {
- if !first || global {
+ for (i, seg) in segments.iter().enumerate() {
+ if i > 0 {
s.push_str("::");
- } else {
- first = false;
}
- s.push_str(&i);
+ if seg.name != keywords::CrateRoot.name() {
+ s.push_str(&*seg.name.as_str());
+ }
}
s
}
type_params: Vec::new(),
where_predicates: Vec::new()
},
- decl: self.decl.clean(cx),
+ decl: (&*self.decl, &[][..]).clean(cx),
abi: self.abi,
}
}
inner: StaticItem(Static {
type_: self.type_.clean(cx),
mutability: self.mutability.clean(cx),
- expr: pprust::expr_to_string(&self.expr),
+ expr: print_const_expr(cx, self.expr),
}),
}
}
deprecation: self.depr.clean(cx),
inner: ConstantItem(Constant {
type_: self.type_.clean(cx),
- expr: pprust::expr_to_string(&self.expr),
+ expr: print_const_expr(cx, self.expr),
}),
}
}
impl Clean<Item> for hir::ForeignItem {
fn clean(&self, cx: &DocContext) -> Item {
let inner = match self.node {
- hir::ForeignItemFn(ref decl, ref generics) => {
+ hir::ForeignItemFn(ref decl, ref names, ref generics) => {
ForeignFunctionItem(Function {
- decl: decl.clean(cx),
+ decl: (&**decl, &names[..]).clean(cx),
generics: generics.clean(cx),
unsafety: hir::Unsafety::Unsafe,
abi: Abi::Rust,
}
}
+fn print_const_expr(cx: &DocContext, body: hir::BodyId) -> String {
+ cx.tcx.map.node_to_pretty_string(body.node_id)
+}
+
/// Given a type Path, resolve it to a Type using the TyCtxt
fn resolve_type(cx: &DocContext,
path: Path,
pub whence: Span,
pub generics: hir::Generics,
pub abi: abi::Abi,
+ pub body: hir::BodyId,
}
pub struct Typedef {
pub struct Static {
pub type_: P<hir::Ty>,
pub mutability: hir::Mutability,
- pub expr: P<hir::Expr>,
+ pub expr: hir::BodyId,
pub name: Name,
pub attrs: hir::HirVec<ast::Attribute>,
pub vis: hir::Visibility,
pub struct Constant {
pub type_: P<hir::Ty>,
- pub expr: P<hir::Expr>,
+ pub expr: hir::BodyId,
pub name: Name,
pub attrs: hir::HirVec<ast::Attribute>,
pub vis: hir::Visibility,
if !f.alternate() {
clause.push_str("</span>");
let plain = format!("{:#}", self);
- if plain.len() > 80 {
+ if plain.len() + pad > 80 {
//break it onto its own line regardless, but make sure method impls and trait
//blocks keep their fixed padding (2 and 9, respectively)
let padding = if pad > 10 {
<title>{title}</title>
+ <link rel="stylesheet" type="text/css" href="{root_path}normalize.css">
<link rel="stylesheet" type="text/css" href="{root_path}rustdoc.css">
<link rel="stylesheet" type="text/css" href="{root_path}main.css">
{css_extension}
ty: item.type_(),
name: item.name.clone().unwrap(),
path: fqp[..fqp.len() - 1].join("::"),
- desc: Escape(&shorter(item.doc_value())).to_string(),
+ desc: plain_summary_line(item.doc_value()),
parent: Some(did),
parent_idx: None,
search_type: get_index_search_type(&item),
}
let crate_doc = krate.module.as_ref().map(|module| {
- Escape(&shorter(module.doc_value())).to_string()
+ plain_summary_line(module.doc_value())
}).unwrap_or(String::new());
let mut crate_data = BTreeMap::new();
ty: item.type_(),
name: s.to_string(),
path: path.join("::").to_string(),
- desc: Escape(&shorter(item.doc_value())).to_string(),
+ desc: plain_summary_line(item.doc_value()),
parent: parent,
parent_idx: None,
search_type: get_index_search_type(&item),
}
fn document_stability(w: &mut fmt::Formatter, cx: &Context, item: &clean::Item) -> fmt::Result {
- for stability in short_stability(item, cx, true) {
- write!(w, "<div class='stability'>{}</div>", stability)?;
+ let stabilities = short_stability(item, cx, true);
+ if !stabilities.is_empty() {
+ write!(w, "<div class='stability'>")?;
+ for stability in stabilities {
+ write!(w, "{}", stability)?;
+ }
+ write!(w, "</div>")?;
}
Ok(())
}
String::new()
};
let text = format!("Deprecated{}{}", since, Markdown(&deprecated_reason));
- stability.push(format!("<em class='stab deprecated'>{}</em>", text))
+ stability.push(format!("<div class='stab deprecated'>{}</div>", text))
};
if stab.level == stability::Unstable {
String::new()
};
let text = format!("Unstable{}{}", unstable_extra, Markdown(&unstable_reason));
- stability.push(format!("<em class='stab unstable'>{}</em>", text))
+ stability.push(format!("<div class='stab unstable'>{}</div>", text))
};
} else if let Some(depr) = item.deprecation.as_ref() {
let note = if show_reason && !depr.note.is_empty() {
};
let text = format!("Deprecated{}{}", since, Markdown(¬e));
- stability.push(format!("<em class='stab deprecated'>{}</em>", text))
+ stability.push(format!("<div class='stab deprecated'>{}</div>", text))
}
stability
displayPath + '<span class="' + type + '">' +
name + '</span></a></td><td>' +
'<a href="' + href + '">' +
- '<span class="desc">' + item.desc +
+ '<span class="desc">' + escape(item.desc) +
' </span></a></td></tr>';
});
} else {
search();
}
- function plainSummaryLine(markdown) {
- markdown.replace(/\n/g, ' ')
- .replace(/'/g, "\'")
- .replace(/^#+? (.+?)/, "$1")
- .replace(/\[(.*?)\]\(.*?\)/g, "$1")
- .replace(/\[(.*?)\]\[.*?\]/g, "$1");
- }
-
index = buildIndex(rawSearchIndex);
startSearch();
if (crates[i] === window.currentCrate) {
klass += ' current';
}
- if (rawSearchIndex[crates[i]].items[0]) {
- var desc = rawSearchIndex[crates[i]].items[0][3];
- var link = $('<a>', {'href': '../' + crates[i] + '/index.html',
- 'title': plainSummaryLine(desc),
- 'class': klass}).text(crates[i]);
- ul.append($('<li>').append(link));
- }
+ var link = $('<a>', {'href': '../' + crates[i] + '/index.html',
+ 'title': rawSearchIndex[crates[i]].doc,
+ 'class': klass}).text(crates[i]);
+ ul.append($('<li>').append(link));
}
sidebar.append(div);
}
-@import "normalize.css";
-
/**
* Copyright 2013 The Rust Project Developers. See the COPYRIGHT
* file at the top-level directory of this distribution and at
padding: 20px;
}
-em.stab {
- display: inline-block;
+.stab {
+ display: table;
border-width: 1px;
border-style: solid;
padding: 3px;
margin-bottom: 5px;
font-size: 90%;
- font-style: normal;
}
-em.stab p {
+.stab p {
display: inline;
}
.module-item .stab {
+ display: inline;
border-width: 0;
padding: 0;
margin: 0;
background-color: white;
}
-div.stability > em > code {
- background-color: initial;
-}
-
.docblock code, .docblock-short code {
background-color: #F5F5F5;
}
background-color: white;
}
-em.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
-em.stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
+.stab.unstable { background: #FFF5D6; border-color: #FFC600; }
+.stab.deprecated { background: #F3DFFF; border-color: #7F0087; }
};
let crate_name = matches.opt_str("crate-name");
let playground_url = matches.opt_str("playground-url");
+ let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from);
match (should_test, markdown_input) {
(true, true) => {
- return markdown::test(input, cfgs, libs, externs, test_args)
+ return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot)
}
(true, false) => {
- return test::run(input, cfgs, libs, externs, test_args, crate_name)
+ return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot)
}
(false, true) => return markdown::render(input,
output.unwrap_or(PathBuf::from("doc")),
/// Run any tests/code examples in the markdown file `input`.
pub fn test(input: &str, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
- mut test_args: Vec<String>) -> isize {
+ mut test_args: Vec<String>, maybe_sysroot: Option<PathBuf>) -> isize {
let input_str = match load_string(input) {
Ok(s) => s,
Err(LoadStringError::ReadFail) => return 1,
let mut opts = TestOptions::default();
opts.no_crate_inject = true;
let mut collector = Collector::new(input.to_string(), cfgs, libs, externs,
- true, opts);
+ true, opts, maybe_sysroot);
find_testable_code(&input_str, &mut collector);
test_args.insert(0, "rustdoctest".to_string());
testing::test_main(&test_args, collector.tests);
libs: SearchPaths,
externs: Externs,
mut test_args: Vec<String>,
- crate_name: Option<String>)
+ crate_name: Option<String>,
+ maybe_sysroot: Option<PathBuf>)
-> isize {
let input_path = PathBuf::from(input);
let input = config::Input::File(input_path.clone());
let sessopts = config::Options {
- maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap()
- .parent().unwrap().to_path_buf()),
+ maybe_sysroot: maybe_sysroot.clone().or_else(
+ || Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())),
search_paths: libs.clone(),
crate_types: vec![config::CrateTypeDylib],
externs: externs.clone(),
libs,
externs,
false,
- opts);
+ opts,
+ maybe_sysroot);
{
let dep_graph = DepGraph::new(false);
fn runtest(test: &str, cratename: &str, cfgs: Vec<String>, libs: SearchPaths,
externs: Externs,
should_panic: bool, no_run: bool, as_test_harness: bool,
- compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions) {
+ compile_fail: bool, mut error_codes: Vec<String>, opts: &TestOptions,
+ maybe_sysroot: Option<PathBuf>) {
// the test harness wants its own `main` & top level functions, so
// never wrap the test in `fn main() { ... }`
let test = maketest(test, Some(cratename), as_test_harness, opts);
let outputs = OutputTypes::new(&[(OutputType::Exe, None)]);
let sessopts = config::Options {
- maybe_sysroot: Some(env::current_exe().unwrap().parent().unwrap()
- .parent().unwrap().to_path_buf()),
+ maybe_sysroot: maybe_sysroot.or_else(
+ || Some(env::current_exe().unwrap().parent().unwrap().parent().unwrap().to_path_buf())),
search_paths: libs,
crate_types: vec![config::CrateTypeExecutable],
output_types: outputs,
current_header: Option<String>,
cratename: String,
opts: TestOptions,
+ maybe_sysroot: Option<PathBuf>,
}
impl Collector {
pub fn new(cratename: String, cfgs: Vec<String>, libs: SearchPaths, externs: Externs,
- use_headers: bool, opts: TestOptions) -> Collector {
+ use_headers: bool, opts: TestOptions, maybe_sysroot: Option<PathBuf>) -> Collector {
Collector {
tests: Vec::new(),
names: Vec::new(),
current_header: None,
cratename: cratename,
opts: opts,
+ maybe_sysroot: maybe_sysroot,
}
}
let externs = self.externs.clone();
let cratename = self.cratename.to_string();
let opts = self.opts.clone();
+ let maybe_sysroot = self.maybe_sysroot.clone();
debug!("Creating test {}: {}", name, test);
self.tests.push(testing::TestDescAndFn {
desc: testing::TestDesc {
as_test_harness,
compile_fail,
error_codes,
- &opts);
+ &opts,
+ maybe_sysroot);
})
});
}
fn visit_item(&mut self, item: &'hir hir::Item) {
let name = if let hir::ItemImpl(.., ref ty, _) = item.node {
- hir::print::ty_to_string(ty)
+ self.map.node_to_pretty_string(ty.id)
} else {
item.name.to_string()
};
unsafety: &hir::Unsafety,
constness: hir::Constness,
abi: &abi::Abi,
- gen: &hir::Generics) -> Function {
+ gen: &hir::Generics,
+ body: hir::BodyId) -> Function {
debug!("Visiting fn");
Function {
id: item.id,
unsafety: *unsafety,
constness: constness,
abi: *abi,
+ body: body,
}
}
om.structs.push(self.visit_variant_data(item, name, sd, gen)),
hir::ItemUnion(ref sd, ref gen) =>
om.unions.push(self.visit_union_data(item, name, sd, gen)),
- hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, _) =>
+ hir::ItemFn(ref fd, ref unsafety, constness, ref abi, ref gen, body) =>
om.fns.push(self.visit_fn(item, name, &**fd, unsafety,
- constness, abi, gen)),
+ constness, abi, gen, body)),
hir::ItemTy(ref ty, ref gen) => {
let t = Typedef {
ty: ty.clone(),
};
om.constants.push(s);
},
- hir::ItemTrait(unsafety, ref gen, ref b, ref items) => {
+ hir::ItemTrait(unsafety, ref gen, ref b, ref item_ids) => {
+ let items = item_ids.iter()
+ .map(|ti| self.cx.tcx.map.trait_item(ti.id).clone())
+ .collect();
let t = Trait {
unsafety: unsafety,
name: name,
- items: items.clone(),
+ items: items,
generics: gen.clone(),
bounds: b.iter().cloned().collect(),
id: item.id,
let target = env::var("TARGET").expect("TARGET was not set");
let host = env::var("HOST").expect("HOST was not set");
if cfg!(feature = "backtrace") && !target.contains("apple") && !target.contains("msvc") &&
- !target.contains("emscripten") && !target.contains("fuchsia") {
+ !target.contains("emscripten") && !target.contains("fuchsia") && !target.contains("redox") {
build_libbacktrace(&host, &target);
}
///
/// # Examples
///
+/// Create a new file and write bytes to it:
+///
/// ```no_run
+/// use std::fs::File;
/// use std::io::prelude::*;
+///
+/// # fn foo() -> std::io::Result<()> {
+/// let mut file = try!(File::create("foo.txt"));
+/// try!(file.write_all(b"Hello, world!"));
+/// # Ok(())
+/// # }
+/// ```
+///
+/// Read the contents of a file into a `String`:
+///
+/// ```no_run
/// use std::fs::File;
+/// use std::io::prelude::*;
///
/// # fn foo() -> std::io::Result<()> {
-/// let mut f = try!(File::create("foo.txt"));
-/// try!(f.write_all(b"Hello, world!"));
+/// let mut file = try!(File::open("foo.txt"));
+/// let mut contents = String::new();
+/// try!(file.read_to_string(&mut contents));
+/// assert_eq!(contents, "Hello, world!");
+/// # Ok(())
+/// # }
+/// ```
+///
+/// It can be more efficient to read the contents of a file with a buffered
+/// [`Read`]er. This can be accomplished with [`BufReader<R>`]:
+///
+/// ```no_run
+/// use std::fs::File;
+/// use std::io::BufReader;
+/// use std::io::prelude::*;
///
-/// let mut f = try!(File::open("foo.txt"));
-/// let mut s = String::new();
-/// try!(f.read_to_string(&mut s));
-/// assert_eq!(s, "Hello, world!");
+/// # fn foo() -> std::io::Result<()> {
+/// let file = try!(File::open("foo.txt"));
+/// let mut buf_reader = BufReader::new(file);
+/// let mut contents = String::new();
+/// try!(buf_reader.read_to_string(&mut contents));
+/// assert_eq!(contents, "Hello, world!");
/// # Ok(())
/// # }
/// ```
+///
+/// [`BufReader`]: ../io/struct.BufReader.html
#[stable(feature = "rust1", since = "1.0.0")]
pub struct File {
inner: fs_imp::File,
}
) }
+ #[cfg(windows)]
+ macro_rules! error { ($e:expr, $s:expr) => (
+ match $e {
+ Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
+ Err(ref err) => assert!(err.raw_os_error() == Some($s),
+ format!("`{}` did not have a code of `{}`", err, $s))
+ }
+ ) }
+
+ #[cfg(unix)]
macro_rules! error { ($e:expr, $s:expr) => (
match $e {
Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s),
match symlink_file(r"nonexisting_target", link) {
Ok(_) => true,
- Err(ref err) =>
- if err.to_string().contains("A required privilege is not held by the client.") {
- false
- } else {
- true
- }
+ // ERROR_PRIVILEGE_NOT_HELD = 1314
+ Err(ref err) if err.raw_os_error() == Some(1314) => false,
+ Err(_) => true,
}
}
let filename = &tmpdir.join("file_that_does_not_exist.txt");
let result = File::open(filename);
- if cfg!(unix) {
- error!(result, "No such file or directory");
- }
- if cfg!(windows) {
- error!(result, "The system cannot find the file specified");
- }
+ #[cfg(unix)]
+ error!(result, "No such file or directory");
+ #[cfg(windows)]
+ error!(result, 2); // ERROR_FILE_NOT_FOUND
}
#[test]
let result = fs::remove_file(filename);
- if cfg!(unix) {
- error!(result, "No such file or directory");
- }
- if cfg!(windows) {
- error!(result, "The system cannot find the file specified");
- }
+ #[cfg(unix)]
+ error!(result, "No such file or directory");
+ #[cfg(windows)]
+ error!(result, 2); // ERROR_FILE_NOT_FOUND
}
#[test]
let mut a = OO::new(); a.append(true);
let mut ra = OO::new(); ra.read(true).append(true);
- let invalid_options = if cfg!(windows) { "The parameter is incorrect" }
- else { "Invalid argument" };
+ #[cfg(windows)]
+ let invalid_options = 87; // ERROR_INVALID_PARAMETER
+ #[cfg(unix)]
+ let invalid_options = "Invalid argument";
// Test various combinations of creation modes and access modes.
//
#[stable(feature = "rust1", since = "1.0.0")]
pub struct LineWriter<W: Write> {
inner: BufWriter<W>,
+ need_flush: bool,
}
impl<W: Write> LineWriter<W> {
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn with_capacity(cap: usize, inner: W) -> LineWriter<W> {
- LineWriter { inner: BufWriter::with_capacity(cap, inner) }
+ LineWriter {
+ inner: BufWriter::with_capacity(cap, inner),
+ need_flush: false,
+ }
}
/// Gets a reference to the underlying writer.
#[stable(feature = "rust1", since = "1.0.0")]
pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
- IntoInnerError(LineWriter { inner: buf }, e)
+ IntoInnerError(LineWriter {
+ inner: buf,
+ need_flush: false,
+ }, e)
})
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write> Write for LineWriter<W> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- match memchr::memrchr(b'\n', buf) {
- Some(i) => {
- let n = self.inner.write(&buf[..i + 1])?;
- if n != i + 1 || self.inner.flush().is_err() {
- // Do not return errors on partial writes.
- return Ok(n);
- }
- self.inner.write(&buf[i + 1..]).map(|i| n + i)
- }
- None => self.inner.write(buf),
+ if self.need_flush {
+ self.flush()?;
+ }
+
+ // Find the last newline character in the buffer provided. If found then
+ // we're going to write all the data up to that point and then flush,
+ // otherewise we just write the whole block to the underlying writer.
+ let i = match memchr::memrchr(b'\n', buf) {
+ Some(i) => i,
+ None => return self.inner.write(buf),
+ };
+
+
+ // Ok, we're going to write a partial amount of the data given first
+ // followed by flushing the newline. After we've successfully written
+ // some data then we *must* report that we wrote that data, so future
+ // errors are ignored. We set our internal `need_flush` flag, though, in
+ // case flushing fails and we need to try it first next time.
+ let n = self.inner.write(&buf[..i + 1])?;
+ self.need_flush = true;
+ if self.flush().is_err() || n != i + 1 {
+ return Ok(n)
+ }
+
+ // At this point we successfully wrote `i + 1` bytes and flushed it out,
+ // meaning that the entire line is now flushed out on the screen. While
+ // we can attempt to finish writing the rest of the data provided.
+ // Remember though that we ignore errors here as we've successfully
+ // written data, so we need to report that.
+ match self.inner.write(&buf[i + 1..]) {
+ Ok(i) => Ok(n + i),
+ Err(_) => Ok(n),
}
}
- fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+ fn flush(&mut self) -> io::Result<()> {
+ self.inner.flush()?;
+ self.need_flush = false;
+ Ok(())
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
BufWriter::new(io::sink())
});
}
+
+ struct AcceptOneThenFail {
+ written: bool,
+ flushed: bool,
+ }
+
+ impl Write for AcceptOneThenFail {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ if !self.written {
+ assert_eq!(data, b"a\nb\n");
+ self.written = true;
+ Ok(data.len())
+ } else {
+ Err(io::Error::new(io::ErrorKind::NotFound, "test"))
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ assert!(self.written);
+ assert!(!self.flushed);
+ self.flushed = true;
+ Err(io::Error::new(io::ErrorKind::Other, "test"))
+ }
+ }
+
+ #[test]
+ fn erroneous_flush_retried() {
+ let a = AcceptOneThenFail {
+ written: false,
+ flushed: false,
+ };
+
+ let mut l = LineWriter::new(a);
+ assert_eq!(l.write(b"a\nb\na").unwrap(), 4);
+ assert!(l.get_ref().written);
+ assert!(l.get_ref().flushed);
+ l.get_mut().flushed = false;
+
+ assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other)
+ }
}
/// println!("{}", line.unwrap());
/// }
/// ```
+ ///
+ /// # Errors
+ ///
+ /// Each line of the iterator has the same error semantics as [`BufRead::read_line()`].
+ ///
+ /// [`BufRead::read_line()`]: trait.BufRead.html#method.read_line
#[stable(feature = "rust1", since = "1.0.0")]
fn lines(self) -> Lines<Self> where Self: Sized {
Lines { buf: self }
mod imp {
use os::unix::prelude::*;
use mem;
- use ffi::OsString;
+ use ffi::{CStr, OsString};
use marker::PhantomData;
- use slice;
- use str;
+ use libc;
use super::Args;
use sys_common::mutex::Mutex;
static LOCK: Mutex = Mutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
- let mut args: Vec<Vec<u8>> = Vec::new();
- for i in 0..argc {
- let len = *(argv.offset(i * 2)) as usize;
- let ptr = *(argv.offset(i * 2 + 1));
- args.push(slice::from_raw_parts(ptr, len).to_vec());
- }
+ let args = (0..argc).map(|i| {
+ CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
+ }).collect();
LOCK.lock();
let ptr = get_global_ptr();
#![stable(feature = "rust1", since = "1.0.0")]
use fs;
+use net;
use sys;
-use sys_common::{AsInner, FromInner, IntoInner};
+use sys_common::{self, AsInner, FromInner, IntoInner};
/// Raw file descriptors.
#[stable(feature = "rust1", since = "1.0.0")]
}
}
-/*
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpStream {
- fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_inner().fd().raw()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpListener {
- fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_inner().fd().raw()
+ }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::UdpSocket {
- fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_inner().fd().raw()
+ }
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::TcpStream {
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
- let socket = sys::net::Socket::from_inner(fd);
- net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket))
+ let file = sys::fs::File::from_inner(fd);
+ net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(file))
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
- let socket = sys::net::Socket::from_inner(fd);
- net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket))
+ let file = sys::fs::File::from_inner(fd);
+ net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(file))
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::UdpSocket {
unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
- let socket = sys::net::Socket::from_inner(fd);
- net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket))
+ let file = sys::fs::File::from_inner(fd);
+ net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(file))
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::TcpStream {
fn into_raw_fd(self) -> RawFd {
- self.into_inner().into_socket().into_inner()
+ self.into_inner().into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::TcpListener {
fn into_raw_fd(self) -> RawFd {
- self.into_inner().into_socket().into_inner()
+ self.into_inner().into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::UdpSocket {
fn into_raw_fd(self) -> RawFd {
- self.into_inner().into_socket().into_inner()
+ self.into_inner().into_inner().into_fd().into_raw()
}
}
-*/
name: Box<[u8]>
}
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct OpenOptions {
// generic
read: bool,
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType { mode: u16 }
+#[derive(Debug)]
pub struct DirBuilder { mode: u16 }
impl FileAttr {
}
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
- let flags = syscall::O_CREAT | syscall::O_DIRECTORY | syscall::O_EXCL;
+ let flags = syscall::O_CREAT | syscall::O_CLOEXEC | syscall::O_DIRECTORY | syscall::O_EXCL;
let fd = cvt(syscall::open(p.to_str().unwrap(), flags | (self.mode as usize & 0o777)))?;
let _ = syscall::close(fd);
Ok(())
#![allow(dead_code, missing_docs, bad_style)]
-pub extern crate syscall;
-
use io::{self, ErrorKind};
pub mod args;
+#[cfg(any(not(cargobuild), feature = "backtrace"))]
pub mod backtrace;
pub mod condvar;
pub mod env;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
+pub mod syscall;
pub mod thread;
pub mod thread_local;
pub mod time;
use self::dns::{Dns, DnsQuery};
-pub extern crate libc as netc;
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;
+pub mod netc;
+
mod dns;
mod tcp;
mod udp;
--- /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.
+
+pub type in_addr_t = u32;
+pub type in_port_t = u16;
+
+pub type socklen_t = u32;
+pub type sa_family_t = u16;
+
+pub const AF_INET: sa_family_t = 1;
+pub const AF_INET6: sa_family_t = 2;
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct in_addr {
+ pub s_addr: in_addr_t,
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+ __align: [u32; 0],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr {
+ pub sa_family: sa_family_t,
+ pub sa_data: [u8; 14],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr_in {
+ pub sin_family: sa_family_t,
+ pub sin_port: in_port_t,
+ pub sin_addr: in_addr,
+ pub sin_zero: [u8; 8],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr_in6 {
+ pub sin6_family: sa_family_t,
+ pub sin6_port: in_port_t,
+ pub sin6_flowinfo: u32,
+ pub sin6_addr: in6_addr,
+ pub sin6_scope_id: u32,
+}
use net::{SocketAddr, Shutdown};
use path::Path;
use sys::fs::{File, OpenOptions};
+use sys_common::{AsInner, FromInner, IntoInner};
use time::Duration;
use vec::Vec;
}
}
+impl AsInner<File> for TcpStream {
+ fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for TcpStream {
+ fn from_inner(file: File) -> TcpStream {
+ TcpStream(file)
+ }
+}
+
+impl IntoInner<File> for TcpStream {
+ fn into_inner(self) -> File { self.0 }
+}
+
#[derive(Debug)]
pub struct TcpListener(File);
Err(Error::new(ErrorKind::Other, "TcpListener::set_ttl not implemented"))
}
}
+
+impl AsInner<File> for TcpListener {
+ fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for TcpListener {
+ fn from_inner(file: File) -> TcpListener {
+ TcpListener(file)
+ }
+}
+
+impl IntoInner<File> for TcpListener {
+ fn into_inner(self) -> File { self.0 }
+}
use net::{SocketAddr, Ipv4Addr, Ipv6Addr};
use path::Path;
use sys::fs::{File, OpenOptions};
+use sys_common::{AsInner, FromInner, IntoInner};
use time::Duration;
use super::{path_to_peer_addr, path_to_local_addr};
Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v6 not implemented"))
}
}
+
+impl AsInner<File> for UdpSocket {
+ fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for UdpSocket {
+ fn from_inner(file: File) -> UdpSocket {
+ UdpSocket(file, UnsafeCell::new(None))
+ }
+}
+
+impl IntoInner<File> for UdpSocket {
+ fn into_inner(self) -> File { self.0 }
+}
// except according to those terms.
use io;
-use libc;
use rand::Rng;
-pub struct OsRng;
+// FIXME: Use rand:
+pub struct OsRng {
+ state: [u64; 2]
+}
impl OsRng {
/// Create a new `OsRng`.
pub fn new() -> io::Result<OsRng> {
- Ok(OsRng)
+ Ok(OsRng {
+ state: [0xBADF00D1, 0xDEADBEEF]
+ })
}
}
self.next_u64() as u32
}
fn next_u64(&mut self) -> u64 {
- unsafe { libc::random() }
+ // Store the first and second part.
+ let mut x = self.state[0];
+ let y = self.state[1];
+
+ // Put the second part into the first slot.
+ self.state[0] = y;
+ // Twist the first slot.
+ x ^= x << 23;
+ // Update the second slot.
+ self.state[1] = x ^ y ^ (x >> 17) ^ (y >> 26);
+
+ // Generate the final integer.
+ self.state[1].wrapping_add(y)
+
}
fn fill_bytes(&mut self, buf: &mut [u8]) {
for chunk in buf.chunks_mut(8) {
--- /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 super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b)
+ : "memory", "r0", "r1", "r2", "r3", "r4"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+ -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e), "{r4}"(f)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
--- /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 super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b)
+ : "memory", "ebx", "ecx", "edx", "esi", "edi"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+ -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
--- /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 super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b)
+ : "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8",
+ "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+ -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e), "{rdi}"(f)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
--- /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 super::arch::*;
+use super::data::{Stat, StatVfs, TimeSpec};
+use super::error::Result;
+use super::number::*;
+
+use core::mem;
+
+/// Set the end of the process's heap
+///
+/// When `addr` is `0`, this function will return the current break.
+///
+/// When `addr` is nonzero, this function will attempt to set the end of the process's
+/// heap to `addr` and return the new program break. The new program break should be
+/// checked by the allocator, it may not be exactly `addr`, as it may be aligned to a page
+/// boundary.
+///
+/// On error, `Err(ENOMEM)` will be returned indicating that no memory is available
+pub unsafe fn brk(addr: usize) -> Result<usize> {
+ syscall1(SYS_BRK, addr)
+}
+
+/// Change the process's working directory
+///
+/// This function will attempt to set the process's working directory to `path`, which can be
+/// either a relative, scheme relative, or absolute path.
+///
+/// On success, `Ok(0)` will be returned. On error, one of the following errors will be returned.
+///
+/// # Errors
+///
+/// * `EACCES` - permission is denied for one of the components of `path`, or `path`
+/// * `EFAULT` - `path` does not point to the process's addressible memory
+/// * `EIO` - an I/O error occured
+/// * `ENOENT` - `path` does not exit
+/// * `ENOTDIR` - `path` is not a directory
+pub fn chdir(path: &str) -> Result<usize> {
+ unsafe { syscall2(SYS_CHDIR, path.as_ptr() as usize, path.len()) }
+}
+
+pub fn chmod(path: &str, mode: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_CHMOD, path.as_ptr() as usize, path.len(), mode) }
+}
+
+/// Produce a fork of the current process, or a new process thread
+pub unsafe fn clone(flags: usize) -> Result<usize> {
+ syscall1_clobber(SYS_CLONE, flags)
+}
+
+/// Close a file
+pub fn close(fd: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_CLOSE, fd) }
+}
+
+/// Get the current system time
+pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> {
+ unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
+}
+
+/// Copy and transform a file descriptor
+pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Replace the current process with a new executable
+pub fn execve(path: &str, args: &[[usize; 2]]) -> Result<usize> {
+ unsafe { syscall4(SYS_EXECVE, path.as_ptr() as usize, path.len(),
+ args.as_ptr() as usize, args.len()) }
+}
+
+/// Exit the current process
+pub fn exit(status: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_EXIT, status) }
+}
+
+/// Register a file for event-based I/O
+pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) }
+}
+
+/// Register a file for event-based I/O
+pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_FEVENT, fd, flags) }
+}
+
+/// Map a file into memory
+pub unsafe fn fmap(fd: usize, offset: usize, size: usize) -> Result<usize> {
+ syscall3(SYS_FMAP, fd, offset, size)
+}
+
+/// Unmap a memory-mapped file
+pub unsafe fn funmap(addr: usize) -> Result<usize> {
+ syscall1(SYS_FUNMAP, addr)
+}
+
+/// Retrieve the canonical path of a file
+pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Get metadata about a file
+pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> {
+ unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::<Stat>()) }
+}
+
+/// Get metadata about a filesystem
+pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result<usize> {
+ unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::<StatVfs>()) }
+}
+
+/// Sync a file descriptor to its underlying medium
+pub fn fsync(fd: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_FSYNC, fd) }
+}
+
+/// Truncate or extend a file to a specified length
+pub fn ftruncate(fd: usize, len: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_FTRUNCATE, fd, len) }
+}
+
+/// Fast userspace mutex
+pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32)
+ -> Result<usize> {
+ syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize)
+}
+
+/// Get the current working directory
+pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
+ unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Get the effective group ID
+pub fn getegid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETEGID) }
+}
+
+/// Get the effective namespace
+pub fn getens() -> Result<usize> {
+ unsafe { syscall0(SYS_GETENS) }
+}
+
+/// Get the effective user ID
+pub fn geteuid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETEUID) }
+}
+
+/// Get the current group ID
+pub fn getgid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETGID) }
+}
+
+/// Get the current namespace
+pub fn getns() -> Result<usize> {
+ unsafe { syscall0(SYS_GETNS) }
+}
+
+/// Get the current process ID
+pub fn getpid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETPID) }
+}
+
+/// Get the current user ID
+pub fn getuid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETUID) }
+}
+
+/// Set the I/O privilege level
+pub unsafe fn iopl(level: usize) -> Result<usize> {
+ syscall1(SYS_IOPL, level)
+}
+
+/// Send a signal `sig` to the process identified by `pid`
+pub fn kill(pid: usize, sig: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_KILL, pid, sig) }
+}
+
+/// Create a link to a file
+pub unsafe fn link(old: *const u8, new: *const u8) -> Result<usize> {
+ syscall2(SYS_LINK, old as usize, new as usize)
+}
+
+/// Seek to `offset` bytes in a file descriptor
+pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) }
+}
+
+/// Make a new scheme namespace
+pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> {
+ unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) }
+}
+
+/// Sleep for the time specified in `req`
+pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> {
+ unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize,
+ rem as *mut TimeSpec as usize) }
+}
+
+/// Open a file
+pub fn open(path: &str, flags: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_OPEN, path.as_ptr() as usize, path.len(), flags) }
+}
+
+/// Allocate pages, linearly in physical memory
+pub unsafe fn physalloc(size: usize) -> Result<usize> {
+ syscall1(SYS_PHYSALLOC, size)
+}
+
+/// Free physically allocated pages
+pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> {
+ syscall2(SYS_PHYSFREE, physical_address, size)
+}
+
+/// Map physical memory to virtual memory
+pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
+ syscall3(SYS_PHYSMAP, physical_address, size, flags)
+}
+
+/// Unmap previously mapped physical memory
+pub unsafe fn physunmap(virtual_address: usize) -> Result<usize> {
+ syscall1(SYS_PHYSUNMAP, virtual_address)
+}
+
+/// Create a pair of file descriptors referencing the read and write ends of a pipe
+pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) }
+}
+
+/// Read from a file descriptor into a buffer
+pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Remove a directory
+pub fn rmdir(path: &str) -> Result<usize> {
+ unsafe { syscall2(SYS_RMDIR, path.as_ptr() as usize, path.len()) }
+}
+
+/// Set the current process group IDs
+pub fn setregid(rgid: usize, egid: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETREGID, rgid, egid) }
+}
+
+/// Make a new scheme namespace
+pub fn setrens(rns: usize, ens: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETRENS, rns, ens) }
+}
+
+/// Set the current process user IDs
+pub fn setreuid(ruid: usize, euid: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETREUID, ruid, euid) }
+}
+
+/// Remove a file
+pub fn unlink(path: &str) -> Result<usize> {
+ unsafe { syscall2(SYS_UNLINK, path.as_ptr() as usize, path.len()) }
+}
+
+/// Convert a virtual address to a physical one
+pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> {
+ syscall1(SYS_VIRTTOPHYS, virtual_address)
+}
+
+/// Check if a child process has exited or received a signal
+pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) }
+}
+
+/// Write a buffer to a file descriptor
+///
+/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning
+/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which
+/// were written.
+///
+/// # Errors
+///
+/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block
+/// * `EBADF` - the file descriptor is not valid or is not open for writing
+/// * `EFAULT` - `buf` does not point to the process's addressible memory
+/// * `EIO` - an I/O error occured
+/// * `ENOSPC` - the device containing the file descriptor has no room for data
+/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed
+pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Yield the process's time slice to the kernel
+///
+/// This function will return Ok(0) on success
+pub fn sched_yield() -> Result<usize> {
+ unsafe { syscall0(SYS_YIELD) }
+}
--- /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 core::ops::{Deref, DerefMut};
+use core::{mem, slice};
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct Stat {
+ pub st_dev: u64,
+ pub st_ino: u64,
+ pub st_mode: u16,
+ pub st_nlink: u32,
+ pub st_uid: u32,
+ pub st_gid: u32,
+ pub st_size: u64,
+ pub st_blksize: u32,
+ pub st_blocks: u64,
+ pub st_mtime: u64,
+ pub st_mtime_nsec: u32,
+ pub st_atime: u64,
+ pub st_atime_nsec: u32,
+ pub st_ctime: u64,
+ pub st_ctime_nsec: u32,
+}
+
+impl Deref for Stat {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(self as *const Stat as *const u8,
+ mem::size_of::<Stat>()) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for Stat {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(self as *mut Stat as *mut u8,
+ mem::size_of::<Stat>()) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct StatVfs {
+ pub f_bsize: u32,
+ pub f_blocks: u64,
+ pub f_bfree: u64,
+ pub f_bavail: u64,
+}
+
+impl Deref for StatVfs {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(self as *const StatVfs as *const u8,
+ mem::size_of::<StatVfs>()) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for StatVfs {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(self as *mut StatVfs as *mut u8,
+ mem::size_of::<StatVfs>()) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct TimeSpec {
+ pub tv_sec: i64,
+ pub tv_nsec: i32,
+}
--- /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 core::{fmt, result};
+
+#[derive(Eq, PartialEq)]
+pub struct Error {
+ pub errno: i32,
+}
+
+pub type Result<T> = result::Result<T, Error>;
+
+impl Error {
+ pub fn new(errno: i32) -> Error {
+ Error { errno: errno }
+ }
+
+ pub fn mux(result: Result<usize>) -> usize {
+ match result {
+ Ok(value) => value,
+ Err(error) => -error.errno as usize,
+ }
+ }
+
+ pub fn demux(value: usize) -> Result<usize> {
+ let errno = -(value as i32);
+ if errno >= 1 && errno < STR_ERROR.len() as i32 {
+ Err(Error::new(errno))
+ } else {
+ Ok(value)
+ }
+ }
+
+ pub fn text(&self) -> &str {
+ if let Some(description) = STR_ERROR.get(self.errno as usize) {
+ description
+ } else {
+ "Unknown Error"
+ }
+ }
+}
+
+impl fmt::Debug for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+ f.write_str(self.text())
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
+ f.write_str(self.text())
+ }
+}
+
+pub const EPERM: i32 = 1; /* Operation not permitted */
+pub const ENOENT: i32 = 2; /* No such file or directory */
+pub const ESRCH: i32 = 3; /* No such process */
+pub const EINTR: i32 = 4; /* Interrupted system call */
+pub const EIO: i32 = 5; /* I/O error */
+pub const ENXIO: i32 = 6; /* No such device or address */
+pub const E2BIG: i32 = 7; /* Argument list too long */
+pub const ENOEXEC: i32 = 8; /* Exec format error */
+pub const EBADF: i32 = 9; /* Bad file number */
+pub const ECHILD: i32 = 10; /* No child processes */
+pub const EAGAIN: i32 = 11; /* Try again */
+pub const ENOMEM: i32 = 12; /* Out of memory */
+pub const EACCES: i32 = 13; /* Permission denied */
+pub const EFAULT: i32 = 14; /* Bad address */
+pub const ENOTBLK: i32 = 15; /* Block device required */
+pub const EBUSY: i32 = 16; /* Device or resource busy */
+pub const EEXIST: i32 = 17; /* File exists */
+pub const EXDEV: i32 = 18; /* Cross-device link */
+pub const ENODEV: i32 = 19; /* No such device */
+pub const ENOTDIR: i32 = 20; /* Not a directory */
+pub const EISDIR: i32 = 21; /* Is a directory */
+pub const EINVAL: i32 = 22; /* Invalid argument */
+pub const ENFILE: i32 = 23; /* File table overflow */
+pub const EMFILE: i32 = 24; /* Too many open files */
+pub const ENOTTY: i32 = 25; /* Not a typewriter */
+pub const ETXTBSY: i32 = 26; /* Text file busy */
+pub const EFBIG: i32 = 27; /* File too large */
+pub const ENOSPC: i32 = 28; /* No space left on device */
+pub const ESPIPE: i32 = 29; /* Illegal seek */
+pub const EROFS: i32 = 30; /* Read-only file system */
+pub const EMLINK: i32 = 31; /* Too many links */
+pub const EPIPE: i32 = 32; /* Broken pipe */
+pub const EDOM: i32 = 33; /* Math argument out of domain of func */
+pub const ERANGE: i32 = 34; /* Math result not representable */
+pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */
+pub const ENAMETOOLONG: i32 = 36; /* File name too long */
+pub const ENOLCK: i32 = 37; /* No record locks available */
+pub const ENOSYS: i32 = 38; /* Function not implemented */
+pub const ENOTEMPTY: i32 = 39; /* Directory not empty */
+pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */
+pub const EWOULDBLOCK: i32 = 41; /* Operation would block */
+pub const ENOMSG: i32 = 42; /* No message of desired type */
+pub const EIDRM: i32 = 43; /* Identifier removed */
+pub const ECHRNG: i32 = 44; /* Channel number out of range */
+pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */
+pub const EL3HLT: i32 = 46; /* Level 3 halted */
+pub const EL3RST: i32 = 47; /* Level 3 reset */
+pub const ELNRNG: i32 = 48; /* Link number out of range */
+pub const EUNATCH: i32 = 49; /* Protocol driver not attached */
+pub const ENOCSI: i32 = 50; /* No CSI structure available */
+pub const EL2HLT: i32 = 51; /* Level 2 halted */
+pub const EBADE: i32 = 52; /* Invalid exchange */
+pub const EBADR: i32 = 53; /* Invalid request descriptor */
+pub const EXFULL: i32 = 54; /* Exchange full */
+pub const ENOANO: i32 = 55; /* No anode */
+pub const EBADRQC: i32 = 56; /* Invalid request code */
+pub const EBADSLT: i32 = 57; /* Invalid slot */
+pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */
+pub const EBFONT: i32 = 59; /* Bad font file format */
+pub const ENOSTR: i32 = 60; /* Device not a stream */
+pub const ENODATA: i32 = 61; /* No data available */
+pub const ETIME: i32 = 62; /* Timer expired */
+pub const ENOSR: i32 = 63; /* Out of streams resources */
+pub const ENONET: i32 = 64; /* Machine is not on the network */
+pub const ENOPKG: i32 = 65; /* Package not installed */
+pub const EREMOTE: i32 = 66; /* Object is remote */
+pub const ENOLINK: i32 = 67; /* Link has been severed */
+pub const EADV: i32 = 68; /* Advertise error */
+pub const ESRMNT: i32 = 69; /* Srmount error */
+pub const ECOMM: i32 = 70; /* Communication error on send */
+pub const EPROTO: i32 = 71; /* Protocol error */
+pub const EMULTIHOP: i32 = 72; /* Multihop attempted */
+pub const EDOTDOT: i32 = 73; /* RFS specific error */
+pub const EBADMSG: i32 = 74; /* Not a data message */
+pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */
+pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */
+pub const EBADFD: i32 = 77; /* File descriptor in bad state */
+pub const EREMCHG: i32 = 78; /* Remote address changed */
+pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */
+pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */
+pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */
+pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */
+pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */
+pub const EILSEQ: i32 = 84; /* Illegal byte sequence */
+pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */
+pub const ESTRPIPE: i32 = 86; /* Streams pipe error */
+pub const EUSERS: i32 = 87; /* Too many users */
+pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */
+pub const EDESTADDRREQ: i32 = 89; /* Destination address required */
+pub const EMSGSIZE: i32 = 90; /* Message too long */
+pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */
+pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */
+pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */
+pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */
+pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */
+pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */
+pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */
+pub const EADDRINUSE: i32 = 98; /* Address already in use */
+pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */
+pub const ENETDOWN: i32 = 100; /* Network is down */
+pub const ENETUNREACH: i32 = 101; /* Network is unreachable */
+pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */
+pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */
+pub const ECONNRESET: i32 = 104; /* Connection reset by peer */
+pub const ENOBUFS: i32 = 105; /* No buffer space available */
+pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */
+pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */
+pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */
+pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */
+pub const ETIMEDOUT: i32 = 110; /* Connection timed out */
+pub const ECONNREFUSED: i32 = 111; /* Connection refused */
+pub const EHOSTDOWN: i32 = 112; /* Host is down */
+pub const EHOSTUNREACH: i32 = 113; /* No route to host */
+pub const EALREADY: i32 = 114; /* Operation already in progress */
+pub const EINPROGRESS: i32 = 115; /* Operation now in progress */
+pub const ESTALE: i32 = 116; /* Stale NFS file handle */
+pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */
+pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */
+pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */
+pub const EISNAM: i32 = 120; /* Is a named type file */
+pub const EREMOTEIO: i32 = 121; /* Remote I/O error */
+pub const EDQUOT: i32 = 122; /* Quota exceeded */
+pub const ENOMEDIUM: i32 = 123; /* No medium found */
+pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */
+pub const ECANCELED: i32 = 125; /* Operation Canceled */
+pub const ENOKEY: i32 = 126; /* Required key not available */
+pub const EKEYEXPIRED: i32 = 127; /* Key has expired */
+pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */
+pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */
+pub const EOWNERDEAD: i32 = 130; /* Owner died */
+pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */
+
+pub static STR_ERROR: [&'static str; 132] = ["Success",
+ "Operation not permitted",
+ "No such file or directory",
+ "No such process",
+ "Interrupted system call",
+ "I/O error",
+ "No such device or address",
+ "Argument list too long",
+ "Exec format error",
+ "Bad file number",
+ "No child processes",
+ "Try again",
+ "Out of memory",
+ "Permission denied",
+ "Bad address",
+ "Block device required",
+ "Device or resource busy",
+ "File exists",
+ "Cross-device link",
+ "No such device",
+ "Not a directory",
+ "Is a directory",
+ "Invalid argument",
+ "File table overflow",
+ "Too many open files",
+ "Not a typewriter",
+ "Text file busy",
+ "File too large",
+ "No space left on device",
+ "Illegal seek",
+ "Read-only file system",
+ "Too many links",
+ "Broken pipe",
+ "Math argument out of domain of func",
+ "Math result not representable",
+ "Resource deadlock would occur",
+ "File name too long",
+ "No record locks available",
+ "Function not implemented",
+ "Directory not empty",
+ "Too many symbolic links encountered",
+ "Operation would block",
+ "No message of desired type",
+ "Identifier removed",
+ "Channel number out of range",
+ "Level 2 not synchronized",
+ "Level 3 halted",
+ "Level 3 reset",
+ "Link number out of range",
+ "Protocol driver not attached",
+ "No CSI structure available",
+ "Level 2 halted",
+ "Invalid exchange",
+ "Invalid request descriptor",
+ "Exchange full",
+ "No anode",
+ "Invalid request code",
+ "Invalid slot",
+ "Resource deadlock would occur",
+ "Bad font file format",
+ "Device not a stream",
+ "No data available",
+ "Timer expired",
+ "Out of streams resources",
+ "Machine is not on the network",
+ "Package not installed",
+ "Object is remote",
+ "Link has been severed",
+ "Advertise error",
+ "Srmount error",
+ "Communication error on send",
+ "Protocol error",
+ "Multihop attempted",
+ "RFS specific error",
+ "Not a data message",
+ "Value too large for defined data type",
+ "Name not unique on network",
+ "File descriptor in bad state",
+ "Remote address changed",
+ "Can not access a needed shared library",
+ "Accessing a corrupted shared library",
+ ".lib section in a.out corrupted",
+ "Attempting to link in too many shared libraries",
+ "Cannot exec a shared library directly",
+ "Illegal byte sequence",
+ "Interrupted system call should be restarted",
+ "Streams pipe error",
+ "Too many users",
+ "Socket operation on non-socket",
+ "Destination address required",
+ "Message too long",
+ "Protocol wrong type for socket",
+ "Protocol not available",
+ "Protocol not supported",
+ "Socket type not supported",
+ "Operation not supported on transport endpoint",
+ "Protocol family not supported",
+ "Address family not supported by protocol",
+ "Address already in use",
+ "Cannot assign requested address",
+ "Network is down",
+ "Network is unreachable",
+ "Network dropped connection because of reset",
+ "Software caused connection abort",
+ "Connection reset by peer",
+ "No buffer space available",
+ "Transport endpoint is already connected",
+ "Transport endpoint is not connected",
+ "Cannot send after transport endpoint shutdown",
+ "Too many references: cannot splice",
+ "Connection timed out",
+ "Connection refused",
+ "Host is down",
+ "No route to host",
+ "Operation already in progress",
+ "Operation now in progress",
+ "Stale NFS file handle",
+ "Structure needs cleaning",
+ "Not a XENIX named type file",
+ "No XENIX semaphores available",
+ "Is a named type file",
+ "Remote I/O error",
+ "Quota exceeded",
+ "No medium found",
+ "Wrong medium type",
+ "Operation Canceled",
+ "Required key not available",
+ "Key has expired",
+ "Key has been revoked",
+ "Key was rejected by service",
+ "Owner died",
+ "State not recoverable"];
--- /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.
+
+pub const CLONE_VM: usize = 0x100;
+pub const CLONE_FS: usize = 0x200;
+pub const CLONE_FILES: usize = 0x400;
+pub const CLONE_VFORK: usize = 0x4000;
+
+pub const CLOCK_REALTIME: usize = 1;
+pub const CLOCK_MONOTONIC: usize = 4;
+
+pub const EVENT_NONE: usize = 0;
+pub const EVENT_READ: usize = 1;
+pub const EVENT_WRITE: usize = 2;
+
+pub const F_GETFL: usize = 1;
+pub const F_SETFL: usize = 2;
+
+pub const FUTEX_WAIT: usize = 0;
+pub const FUTEX_WAKE: usize = 1;
+pub const FUTEX_REQUEUE: usize = 2;
+
+pub const MAP_WRITE: usize = 1;
+pub const MAP_WRITE_COMBINE: usize = 2;
+
+pub const MODE_TYPE: u16 = 0xF000;
+pub const MODE_DIR: u16 = 0x4000;
+pub const MODE_FILE: u16 = 0x8000;
+
+pub const MODE_PERM: u16 = 0x0FFF;
+pub const MODE_SETUID: u16 = 0o4000;
+pub const MODE_SETGID: u16 = 0o2000;
+
+pub const O_RDONLY: usize = 0x0001_0000;
+pub const O_WRONLY: usize = 0x0002_0000;
+pub const O_RDWR: usize = 0x0003_0000;
+pub const O_NONBLOCK: usize = 0x0004_0000;
+pub const O_APPEND: usize = 0x0008_0000;
+pub const O_SHLOCK: usize = 0x0010_0000;
+pub const O_EXLOCK: usize = 0x0020_0000;
+pub const O_ASYNC: usize = 0x0040_0000;
+pub const O_FSYNC: usize = 0x0080_0000;
+pub const O_CLOEXEC: usize = 0x0100_0000;
+pub const O_CREAT: usize = 0x0200_0000;
+pub const O_TRUNC: usize = 0x0400_0000;
+pub const O_EXCL: usize = 0x0800_0000;
+pub const O_DIRECTORY: usize = 0x1000_0000;
+pub const O_STAT: usize = 0x2000_0000;
+pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR;
+
+pub const SEEK_SET: usize = 0;
+pub const SEEK_CUR: usize = 1;
+pub const SEEK_END: usize = 2;
+
+pub const SIGHUP: usize = 1;
+pub const SIGINT: usize = 2;
+pub const SIGQUIT: usize = 3;
+pub const SIGILL: usize = 4;
+pub const SIGTRAP: usize = 5;
+pub const SIGABRT: usize = 6;
+pub const SIGBUS: usize = 7;
+pub const SIGFPE: usize = 8;
+pub const SIGKILL: usize = 9;
+pub const SIGUSR1: usize = 10;
+pub const SIGSEGV: usize = 11;
+pub const SIGUSR2: usize = 12;
+pub const SIGPIPE: usize = 13;
+pub const SIGALRM: usize = 14;
+pub const SIGTERM: usize = 15;
+pub const SIGSTKFLT: usize= 16;
+pub const SIGCHLD: usize = 17;
+pub const SIGCONT: usize = 18;
+pub const SIGSTOP: usize = 19;
+pub const SIGTSTP: usize = 20;
+pub const SIGTTIN: usize = 21;
+pub const SIGTTOU: usize = 22;
+pub const SIGURG: usize = 23;
+pub const SIGXCPU: usize = 24;
+pub const SIGXFSZ: usize = 25;
+pub const SIGVTALRM: usize= 26;
+pub const SIGPROF: usize = 27;
+pub const SIGWINCH: usize = 28;
+pub const SIGIO: usize = 29;
+pub const SIGPWR: usize = 30;
+pub const SIGSYS: usize = 31;
+
+pub const WNOHANG: usize = 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.
+
+pub use self::arch::*;
+pub use self::call::*;
+pub use self::data::*;
+pub use self::error::*;
+pub use self::flag::*;
+pub use self::number::*;
+
+#[cfg(target_arch = "arm")]
+#[path="arch/arm.rs"]
+mod arch;
+
+#[cfg(target_arch = "x86")]
+#[path="arch/x86.rs"]
+mod arch;
+
+#[cfg(target_arch = "x86_64")]
+#[path="arch/x86_64.rs"]
+mod arch;
+
+/// Function definitions
+pub mod call;
+
+/// Complex structures that are used for some system calls
+pub mod data;
+
+/// All errors that can be generated by a system call
+pub mod error;
+
+/// Flags used as an argument to many system calls
+pub mod flag;
+
+/// Call numbers used by each system call
+pub mod number;
--- /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.
+
+pub const SYS_CLASS: usize = 0xF000_0000;
+pub const SYS_CLASS_PATH: usize=0x1000_0000;
+pub const SYS_CLASS_FILE: usize=0x2000_0000;
+
+pub const SYS_ARG: usize = 0x0F00_0000;
+pub const SYS_ARG_SLICE: usize =0x0100_0000;
+pub const SYS_ARG_MSLICE: usize=0x0200_0000;
+pub const SYS_ARG_PATH: usize = 0x0300_0000;
+
+pub const SYS_RET: usize = 0x00F0_0000;
+pub const SYS_RET_FILE: usize = 0x0010_0000;
+
+pub const SYS_LINK: usize = SYS_CLASS_PATH | SYS_ARG_PATH | 9;
+pub const SYS_OPEN: usize = SYS_CLASS_PATH | SYS_RET_FILE | 5;
+pub const SYS_CHMOD: usize = SYS_CLASS_PATH | 15;
+pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84;
+pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10;
+
+pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6;
+pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41;
+pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3;
+pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4;
+pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19;
+pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55;
+pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927;
+pub const SYS_FMAP: usize = SYS_CLASS_FILE | 90;
+pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91;
+pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928;
+pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28;
+pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100;
+pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118;
+pub const SYS_FTRUNCATE: usize =SYS_CLASS_FILE | 93;
+
+pub const SYS_BRK: usize = 45;
+pub const SYS_CHDIR: usize = 12;
+pub const SYS_CLOCK_GETTIME: usize = 265;
+pub const SYS_CLONE: usize = 120;
+pub const SYS_EXECVE: usize = 11;
+pub const SYS_EXIT: usize = 1;
+pub const SYS_FUTEX: usize = 240;
+pub const SYS_GETCWD: usize = 183;
+pub const SYS_GETEGID: usize = 202;
+pub const SYS_GETENS: usize = 951;
+pub const SYS_GETEUID: usize = 201;
+pub const SYS_GETGID: usize = 200;
+pub const SYS_GETNS: usize = 950;
+pub const SYS_GETPID: usize = 20;
+pub const SYS_GETUID: usize = 199;
+pub const SYS_IOPL: usize = 110;
+pub const SYS_KILL: usize = 37;
+pub const SYS_MKNS: usize = 984;
+pub const SYS_NANOSLEEP: usize =162;
+pub const SYS_PHYSALLOC: usize =945;
+pub const SYS_PHYSFREE: usize = 946;
+pub const SYS_PHYSMAP: usize = 947;
+pub const SYS_PHYSUNMAP: usize =948;
+pub const SYS_VIRTTOPHYS: usize=949;
+pub const SYS_PIPE2: usize = 331;
+pub const SYS_SETREGID: usize = 204;
+pub const SYS_SETRENS: usize = 952;
+pub const SYS_SETREUID: usize = 203;
+pub const SYS_WAITPID: usize = 7;
+pub const SYS_YIELD: usize = 158;
#![unstable(reason = "not public", issue = "0", feature = "fd")]
+use cmp;
use io::{self, Read};
-use libc::{self, c_int, c_void};
+use libc::{self, c_int, c_void, ssize_t};
use mem;
use sync::atomic::{AtomicBool, Ordering};
use sys::cvt;
fd: c_int,
}
+fn max_len() -> usize {
+ // The maximum read limit on most posix-like systems is `SSIZE_MAX`,
+ // with the man page quoting that if the count of bytes to read is
+ // greater than `SSIZE_MAX` the result is "unspecified".
+ //
+ // On OSX, however, apparently the 64-bit libc is either buggy or
+ // intentionally showing odd behavior by rejecting any read with a size
+ // larger than or equal to INT_MAX. To handle both of these the read
+ // size is capped on both platforms.
+ if cfg!(target_os = "macos") {
+ <c_int>::max_value() as usize - 1
+ } else {
+ <ssize_t>::max_value() as usize
+ }
+}
+
impl FileDesc {
pub fn new(fd: c_int) -> FileDesc {
FileDesc { fd: fd }
let ret = cvt(unsafe {
libc::read(self.fd,
buf.as_mut_ptr() as *mut c_void,
- buf.len())
+ cmp::min(buf.len(), max_len()))
})?;
Ok(ret as usize)
}
unsafe {
cvt_pread64(self.fd,
buf.as_mut_ptr() as *mut c_void,
- buf.len(),
+ cmp::min(buf.len(), max_len()),
offset as i64)
.map(|n| n as usize)
}
let ret = cvt(unsafe {
libc::write(self.fd,
buf.as_ptr() as *const c_void,
- buf.len())
+ cmp::min(buf.len(), max_len()))
})?;
Ok(ret as usize)
}
unsafe {
cvt_pwrite64(self.fd,
buf.as_ptr() as *const c_void,
- buf.len(),
+ cmp::min(buf.len(), max_len()),
offset as i64)
.map(|n| n as usize)
}
pub type mx_status_t = i32;
pub type mx_size_t = usize;
-pub type mx_ssize_t = isize;
pub const MX_HANDLE_INVALID: mx_handle_t = 0;
ExceptionCollidedUnwind
}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct CONSOLE_READCONSOLE_CONTROL {
+ pub nLength: ULONG,
+ pub nInitialChars: ULONG,
+ pub dwCtrlWakeupMask: ULONG,
+ pub dwControlKeyState: ULONG,
+}
+pub type PCONSOLE_READCONSOLE_CONTROL = *mut CONSOLE_READCONSOLE_CONTROL;
+
#[link(name = "ws2_32")]
#[link(name = "userenv")]
#[link(name = "shell32")]
pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
- // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL
pub fn ReadConsoleW(hConsoleInput: HANDLE,
lpBuffer: LPVOID,
nNumberOfCharsToRead: DWORD,
lpNumberOfCharsRead: LPDWORD,
- pInputControl: LPVOID) -> BOOL;
+ pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;
pub fn WriteConsoleW(hConsoleOutput: HANDLE,
lpBuffer: LPCVOID,
use sys::c;
use sys::cvt;
use sys_common::io::read_to_end_uninitialized;
-use u32;
/// An owned container for `HANDLE` object, closing them on Drop.
///
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let mut read = 0;
- // ReadFile takes a DWORD (u32) for the length so it only supports
- // reading u32::MAX bytes at a time.
- let len = cmp::min(buf.len(), u32::MAX as usize) as c::DWORD;
+ let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
let res = cvt(unsafe {
c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID,
len, &mut read, ptr::null_mut())
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let mut amt = 0;
- // WriteFile takes a DWORD (u32) for the length so it only supports
- // writing u32::MAX bytes at a time.
- let len = cmp::min(buf.len(), u32::MAX as usize) as c::DWORD;
+ let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD;
cvt(unsafe {
c::WriteFile(self.0, buf.as_ptr() as c::LPVOID,
len, &mut amt, ptr::null_mut())
if utf8.position() as usize == utf8.get_ref().len() {
let mut utf16 = vec![0u16; 0x1000];
let mut num = 0;
+ let mut input_control = readconsole_input_control(CTRL_Z_MASK);
cvt(unsafe {
c::ReadConsoleW(handle,
utf16.as_mut_ptr() as c::LPVOID,
utf16.len() as u32,
&mut num,
- ptr::null_mut())
+ &mut input_control as c::PCONSOLE_READCONSOLE_CONTROL)
})?;
utf16.truncate(num as usize);
// FIXME: what to do about this data that has already been read?
- let data = match String::from_utf16(&utf16) {
+ let mut data = match String::from_utf16(&utf16) {
Ok(utf8) => utf8.into_bytes(),
Err(..) => return Err(invalid_encoding()),
};
+ if let Output::Console(_) = self.handle {
+ if let Some(&last_byte) = data.last() {
+ if last_byte == CTRL_Z {
+ data.pop();
+ }
+ }
+ }
*utf8 = Cursor::new(data);
}
io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode")
}
+fn readconsole_input_control(wakeup_mask: c::ULONG) -> c::CONSOLE_READCONSOLE_CONTROL {
+ c::CONSOLE_READCONSOLE_CONTROL {
+ nLength: ::mem::size_of::<c::CONSOLE_READCONSOLE_CONTROL>() as c::ULONG,
+ nInitialChars: 0,
+ dwCtrlWakeupMask: wakeup_mask,
+ dwControlKeyState: 0,
+ }
+}
+
+const CTRL_Z: u8 = 0x1A;
+const CTRL_Z_MASK: c::ULONG = 0x4000000; //1 << 0x1A
+
pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32;
// The default buffer capacity is 64k, but apparently windows
// doesn't like 64k reads on stdin. See #13304 for details, but the
/// Thread configuration. Provides detailed control over the properties
/// and behavior of new threads.
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// let builder = thread::Builder::new();
+///
+/// let handler = builder.spawn(|| {
+/// // thread code
+/// }).unwrap();
+///
+/// handler.join().unwrap();
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[derive(Debug)]
pub struct Builder {
impl Builder {
/// Generates the base configuration for spawning a thread, from which
/// configuration methods can be chained.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new()
+ /// .name("foo".into())
+ /// .stack_size(10);
+ ///
+ /// let handler = builder.spawn(|| {
+ /// // thread code
+ /// }).unwrap();
+ ///
+ /// handler.join().unwrap();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn new() -> Builder {
Builder {
///
/// # Examples
///
- /// ```rust
+ /// ```
/// use std::thread;
///
/// let builder = thread::Builder::new()
}
/// Sets the size of the stack for the new thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new().stack_size(10);
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn stack_size(mut self, size: usize) -> Builder {
self.stack_size = Some(size);
///
/// # Errors
///
- /// Unlike the `spawn` free function, this method yields an
- /// `io::Result` to capture any failure to create the thread at
+ /// Unlike the [`spawn`] free function, this method yields an
+ /// [`io::Result`] to capture any failure to create the thread at
/// the OS level.
+ ///
+ /// [`spawn`]: ../../std/thread/fn.spawn.html
+ /// [`io::Result`]: ../../std/io/type.Result.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new();
+ ///
+ /// let handler = builder.spawn(|| {
+ /// // thread code
+ /// }).unwrap();
+ ///
+ /// handler.join().unwrap();
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn spawn<F, T>(self, f: F) -> io::Result<JoinHandle<T>> where
F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
// Free functions
////////////////////////////////////////////////////////////////////////////////
-/// Spawns a new thread, returning a `JoinHandle` for it.
+/// Spawns a new thread, returning a [`JoinHandle`] for it.
///
/// The join handle will implicitly *detach* the child thread upon being
/// dropped. In this case, the child thread may outlive the parent (unless
/// the parent thread is the main thread; the whole process is terminated when
-/// the main thread finishes.) Additionally, the join handle provides a `join`
+/// the main thread finishes). Additionally, the join handle provides a [`join`]
/// method that can be used to join the child thread. If the child thread
-/// panics, `join` will return an `Err` containing the argument given to
-/// `panic`.
+/// panics, [`join`] will return an [`Err`] containing the argument given to
+/// [`panic`].
///
/// # Panics
///
-/// Panics if the OS fails to create a thread; use `Builder::spawn`
+/// Panics if the OS fails to create a thread; use [`Builder::spawn`]
/// to recover from such errors.
+///
+/// [`JoinHandle`]: ../../std/thread/struct.JoinHandle.html
+/// [`join`]: ../../std/thread/struct.JoinHandle.html#method.join
+/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+/// [`panic!`]: ../../std/macro.panic.html
+/// [`Builder::spawn`]: ../../std/thread/struct.Builder.html#method.spawn
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// let handler = thread::spawn(|| {
+/// // thread code
+/// });
+///
+/// handler.join().unwrap();
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn spawn<F, T>(f: F) -> JoinHandle<T> where
F: FnOnce() -> T, F: Send + 'static, T: Send + 'static
/// Gets a handle to the thread that invokes it.
///
-/// #Examples
+/// # Examples
///
/// Getting a handle to the current thread with `thread::current()`:
///
}
/// Cooperatively gives up a timeslice to the OS scheduler.
+///
+/// # Examples
+///
+/// ```
+/// use std::thread;
+///
+/// thread::yield_now();
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn yield_now() {
imp::Thread::yield_now()
///
/// # Examples
///
-/// ```rust,should_panic
+/// ```should_panic
/// use std::thread;
///
/// struct SomeStruct;
/// specifics or platform-dependent functionality. Note that on unix platforms
/// this function will not return early due to a signal being received or a
/// spurious wakeup.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+///
+/// // Let's sleep for 2 seconds:
+/// thread::sleep_ms(2000);
+/// ```
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_deprecated(since = "1.6.0", reason = "replaced by `std::thread::sleep`")]
pub fn sleep_ms(ms: u32) {
///
/// # Examples
///
-/// ```rust,no_run
+/// ```no_run
/// use std::{thread, time};
///
/// let ten_millis = time::Duration::from_millis(10);
///
/// A `JoinHandle` *detaches* the child thread when it is dropped.
///
-/// Due to platform restrictions, it is not possible to `Clone` this
+/// Due to platform restrictions, it is not possible to [`Clone`] this
/// handle: the ability to join a child thread is a uniquely-owned
/// permission.
///
///
/// Creation from [`thread::spawn`]:
///
-/// ```rust
+/// ```
/// use std::thread;
///
/// let join_handle: thread::JoinHandle<_> = thread::spawn(|| {
///
/// Creation from [`thread::Builder::spawn`]:
///
-/// ```rust
+/// ```
/// use std::thread;
///
/// let builder = thread::Builder::new();
/// }).unwrap();
/// ```
///
+/// [`Clone`]: ../../std/clone/trait.Clone.html
/// [`thread::spawn`]: fn.spawn.html
/// [`thread::Builder::spawn`]: struct.Builder.html#method.spawn
#[stable(feature = "rust1", since = "1.0.0")]
pub struct JoinHandle<T>(JoinInner<T>);
impl<T> JoinHandle<T> {
- /// Extracts a handle to the underlying thread
+ /// Extracts a handle to the underlying thread.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(thread_id)]
+ ///
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new();
+ ///
+ /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
+ /// // some work here
+ /// }).unwrap();
+ ///
+ /// let thread = join_handle.thread();
+ /// println!("thread id: {:?}", thread.id());
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn thread(&self) -> &Thread {
&self.0.thread
/// Waits for the associated thread to finish.
///
- /// If the child thread panics, `Err` is returned with the parameter given
- /// to `panic`.
+ /// If the child thread panics, [`Err`] is returned with the parameter given
+ /// to [`panic`].
+ ///
+ /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
+ /// [`panic!`]: ../../std/macro.panic.html
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::thread;
+ ///
+ /// let builder = thread::Builder::new();
+ ///
+ /// let join_handle: thread::JoinHandle<_> = builder.spawn(|| {
+ /// // some work here
+ /// }).unwrap();
+ /// join_handle.join().expect("Couldn't join on the associated thread");
+ /// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn join(mut self) -> Result<T> {
self.0.join()
Aapcs,
Win64,
SysV64,
+ PtxKernel,
// Multiplatform / generic ABIs
Rust,
AbiData {abi: Abi::Aapcs, name: "aapcs", generic: false },
AbiData {abi: Abi::Win64, name: "win64", generic: false },
AbiData {abi: Abi::SysV64, name: "sysv64", generic: false },
+ AbiData {abi: Abi::PtxKernel, name: "ptx-kernel", generic: false },
// Cross-platform ABIs
AbiData {abi: Abi::Rust, name: "Rust", generic: true },
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash)]
pub struct Path {
pub span: Span,
- /// A `::foo` path, is relative to the crate root rather than current
- /// module (like paths in an import).
- pub global: bool,
/// The segments in the path: the things separated by `::`.
+ /// Global paths begin with `keywords::CrateRoot`.
pub segments: Vec<PathSegment>,
}
pub fn from_ident(s: Span, identifier: Ident) -> Path {
Path {
span: s,
- global: false,
segments: vec![identifier.into()],
}
}
+
+ pub fn default_to_global(mut self) -> Path {
+ let name = self.segments[0].identifier.name;
+ if !self.is_global() && name != "$crate" &&
+ name != keywords::SelfValue.name() && name != keywords::Super.name() {
+ self.segments.insert(0, PathSegment::crate_root());
+ }
+ self
+ }
+
+ pub fn is_global(&self) -> bool {
+ !self.segments.is_empty() && self.segments[0].identifier.name == keywords::CrateRoot.name()
+ }
}
/// A segment of a path: an identifier, an optional lifetime, and a set of types.
}
}
+impl PathSegment {
+ pub fn crate_root() -> Self {
+ PathSegment {
+ identifier: keywords::CrateRoot.ident(),
+ parameters: None,
+ }
+ }
+}
+
/// Parameters of a path segment.
///
/// E.g. `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`
}
pub fn from_self(eself: ExplicitSelf, eself_ident: SpannedIdent) -> Arg {
+ let span = mk_sp(eself.span.lo, eself_ident.span.hi);
let infer_ty = P(Ty {
id: DUMMY_NODE_ID,
node: TyKind::ImplicitSelf,
- span: DUMMY_SP,
+ span: span,
});
- let arg = |mutbl, ty, span| Arg {
+ let arg = |mutbl, ty| Arg {
pat: P(Pat {
id: DUMMY_NODE_ID,
node: PatKind::Ident(BindingMode::ByValue(mutbl), eself_ident, None),
id: DUMMY_NODE_ID,
};
match eself.node {
- SelfKind::Explicit(ty, mutbl) => {
- arg(mutbl, ty, mk_sp(eself.span.lo, eself_ident.span.hi))
- }
- SelfKind::Value(mutbl) => arg(mutbl, infer_ty, eself.span),
+ SelfKind::Explicit(ty, mutbl) => arg(mutbl, ty),
+ SelfKind::Value(mutbl) => arg(mutbl, infer_ty),
SelfKind::Region(lt, mutbl) => arg(Mutability::Immutable, P(Ty {
id: DUMMY_NODE_ID,
node: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl: mutbl }),
- span: DUMMY_SP,
- }), eself.span),
+ span: span,
+ })),
}
}
}
}
}
-/*
- FIXME (#3300): Should allow items to be anonymous. Right now
- we just use dummy names for anon items.
- */
/// An item
///
/// The name might be a dummy name in case of anonymous items
fn next_node_id(&mut self) -> ast::NodeId;
fn get_module_scope(&mut self, id: ast::NodeId) -> Mark;
fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item>;
+ fn is_whitelisted_legacy_custom_derive(&self, name: Name) -> bool;
fn visit_expansion(&mut self, mark: Mark, expansion: &Expansion);
fn add_ext(&mut self, ident: ast::Ident, ext: Rc<SyntaxExtension>);
fn next_node_id(&mut self) -> ast::NodeId { ast::DUMMY_NODE_ID }
fn get_module_scope(&mut self, _id: ast::NodeId) -> Mark { Mark::root() }
fn eliminate_crate_var(&mut self, item: P<ast::Item>) -> P<ast::Item> { item }
+ fn is_whitelisted_legacy_custom_derive(&self, _name: Name) -> bool { false }
fn visit_expansion(&mut self, _invoc: Mark, _expansion: &Expansion) {}
fn add_ext(&mut self, _ident: ast::Ident, _ext: Rc<SyntaxExtension>) {}
bindings: Vec<ast::TypeBinding> )
-> ast::Path {
let last_identifier = idents.pop().unwrap();
- let mut segments: Vec<ast::PathSegment> = idents.into_iter().map(Into::into).collect();
+ let mut segments: Vec<ast::PathSegment> = Vec::new();
+ if global {
+ segments.push(ast::PathSegment::crate_root());
+ }
+
+ segments.extend(idents.into_iter().map(Into::into));
let parameters = if lifetimes.is_empty() && types.is_empty() && bindings.is_empty() {
None
} else {
segments.push(ast::PathSegment { identifier: last_identifier, parameters: parameters });
ast::Path {
span: sp,
- global: global,
segments: segments,
}
}
pub fn placeholder(kind: ExpansionKind, id: ast::NodeId) -> Expansion {
fn mac_placeholder() -> ast::Mac {
dummy_spanned(ast::Mac_ {
- path: ast::Path { span: DUMMY_SP, global: false, segments: Vec::new() },
+ path: ast::Path { span: DUMMY_SP, segments: Vec::new() },
tts: Vec::new(),
})
}
// Allow safe suggestions for potential type conversions.
(active, safe_suggestion, "1.0.0", Some(37384)),
+
+ // `extern "ptx-*" fn()`
+ (active, abi_ptx, "1.15.0", None),
);
declare_features! (
gate_feature_post!(&self, abi_sysv64, span,
"sysv64 ABI is experimental and subject to change");
},
- _ => {}
+ Abi::PtxKernel => {
+ gate_feature_post!(&self, abi_ptx, span,
+ "PTX ABIs are experimental and subject to change");
+ }
+ // Stable
+ Abi::Cdecl |
+ Abi::Stdcall |
+ Abi::Fastcall |
+ Abi::Aapcs |
+ Abi::Win64 |
+ Abi::Rust |
+ Abi::C |
+ Abi::System => {}
}
}
}
view_path.map(|Spanned {node, span}| Spanned {
node: match node {
ViewPathSimple(ident, path) => {
- ViewPathSimple(ident, fld.fold_path(path))
+ ViewPathSimple(fld.fold_ident(ident), fld.fold_path(path))
}
ViewPathGlob(path) => {
ViewPathGlob(fld.fold_path(path))
}
ViewPathList(path, path_list_idents) => {
- ViewPathList(fld.fold_path(path),
- path_list_idents.move_map(|path_list_ident| {
- Spanned {
- node: PathListItem_ {
- id: fld.new_id(path_list_ident.node.id),
- rename: path_list_ident.node.rename,
- name: path_list_ident.node.name,
- },
- span: fld.new_span(path_list_ident.span)
- }
- }))
+ let path = fld.fold_path(path);
+ let path_list_idents = path_list_idents.move_map(|path_list_ident| Spanned {
+ node: PathListItem_ {
+ id: fld.new_id(path_list_ident.node.id),
+ rename: path_list_ident.node.rename.map(|ident| fld.fold_ident(ident)),
+ name: fld.fold_ident(path_list_ident.node.name),
+ },
+ span: fld.new_span(path_list_ident.span)
+ });
+ ViewPathList(path, path_list_idents)
}
},
span: fld.new_span(span)
pub fn noop_fold_ty_binding<T: Folder>(b: TypeBinding, fld: &mut T) -> TypeBinding {
TypeBinding {
id: fld.new_id(b.id),
- ident: b.ident,
+ ident: fld.fold_ident(b.ident),
ty: fld.fold_ty(b.ty),
span: fld.new_span(b.span),
}
i
}
-pub fn noop_fold_path<T: Folder>(Path {global, segments, span}: Path, fld: &mut T) -> Path {
+pub fn noop_fold_path<T: Folder>(Path { segments, span }: Path, fld: &mut T) -> Path {
Path {
- global: global,
segments: segments.move_map(|PathSegment {identifier, parameters}| PathSegment {
identifier: fld.fold_ident(identifier),
parameters: parameters.map(|ps| ps.map(|ps| fld.fold_path_parameters(ps))),
.collect::<Vec<_>>()
.into(),
id: fld.new_id(id),
- ident: ident,
+ ident: fld.fold_ident(ident),
bounds: fld.fold_bounds(bounds),
default: default.map(|x| fld.fold_ty(x)),
span: span
let fs = fields.move_map(|f| {
Spanned { span: folder.new_span(f.span),
node: ast::FieldPat {
- ident: f.node.ident,
+ ident: folder.fold_ident(f.node.ident),
pat: folder.fold_pat(f.node.pat),
is_shorthand: f.node.is_shorthand,
}}
id: ast::DUMMY_NODE_ID,
node: ast::ExprKind::Path(None, ast::Path {
span: sp(0, 1),
- global: false,
segments: vec![Ident::from_str("a").into()],
}),
span: sp(0, 1),
id: ast::DUMMY_NODE_ID,
node: ast::ExprKind::Path(None, ast::Path {
span: sp(0, 6),
- global: true,
- segments: vec![Ident::from_str("a").into(), Ident::from_str("b").into()],
+ segments: vec![ast::PathSegment::crate_root(),
+ Ident::from_str("a").into(),
+ Ident::from_str("b").into()]
}),
span: sp(0, 6),
attrs: ThinVec::new(),
id: ast::DUMMY_NODE_ID,
node:ast::ExprKind::Path(None, ast::Path{
span: sp(7, 8),
- global: false,
segments: vec![Ident::from_str("d").into()],
}),
span:sp(7,8),
id: ast::DUMMY_NODE_ID,
node: ast::ExprKind::Path(None, ast::Path {
span:sp(0,1),
- global:false,
segments: vec![Ident::from_str("b").into()],
}),
span: sp(0,1),
ty: P(ast::Ty{id: ast::DUMMY_NODE_ID,
node: ast::TyKind::Path(None, ast::Path{
span:sp(10,13),
- global:false,
segments: vec![Ident::from_str("i32").into()],
}),
span:sp(10,13)
node: ast::ExprKind::Path(None,
ast::Path{
span:sp(17,18),
- global:false,
segments: vec![Ident::from_str("b").into()],
}),
span: sp(17,18),
} else {
ast::Path {
span: span,
- global: false,
segments: vec![]
}
};
// Parse any number of segments and bound sets. A segment is an
// identifier followed by an optional lifetime and a set of types.
// A bound set is a set of type parameter bounds.
- let segments = match mode {
+ let mut segments = match mode {
PathStyle::Type => {
self.parse_path_segments_without_colons()?
}
}
};
+ if is_global {
+ segments.insert(0, ast::PathSegment::crate_root());
+ }
+
// Assemble the span.
let span = mk_sp(lo, self.prev_span.hi);
// Assemble the result.
Ok(ast::Path {
span: span,
- global: is_global,
segments: segments,
})
}
return Ok(where_clause);
}
+ // This is a temporary hack.
+ //
+ // We are considering adding generics to the `where` keyword as an alternative higher-rank
+ // parameter syntax (as in `where<'a>` or `where<T>`. To avoid that being a breaking
+ // change, for now we refuse to parse `where < (ident | lifetime) (> | , | :)`.
+ if token::Lt == self.token {
+ let ident_or_lifetime = self.look_ahead(1, |t| t.is_ident() || t.is_lifetime());
+ if ident_or_lifetime {
+ let gt_comma_or_colon = self.look_ahead(2, |t| {
+ *t == token::Gt || *t == token::Comma || *t == token::Colon
+ });
+ if gt_comma_or_colon {
+ self.span_err(self.span, "syntax `where<T>` is reserved for future use");
+ }
+ }
+ }
+
let mut parsed_something = false;
loop {
let lo = self.span.lo;
} else if self.eat_keyword(keywords::Crate) {
pub_crate(self)
} else {
- let path = self.parse_path(PathStyle::Mod)?;
+ let path = self.parse_path(PathStyle::Mod)?.default_to_global();
self.expect(&token::CloseDelim(token::Paren))?;
Ok(Visibility::Restricted { path: P(path), id: ast::DUMMY_NODE_ID })
}
if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) ||
self.is_import_coupler() {
// `{foo, bar}`, `::{foo, bar}`, `*`, or `::*`.
+ self.eat(&token::ModSep);
let prefix = ast::Path {
- global: self.eat(&token::ModSep),
- segments: Vec::new(),
+ segments: vec![ast::PathSegment::crate_root()],
span: mk_sp(lo, self.span.hi),
};
let view_path_kind = if self.eat(&token::BinOp(token::Star)) {
};
Ok(P(spanned(lo, self.span.hi, view_path_kind)))
} else {
- let prefix = self.parse_path(PathStyle::Mod)?;
+ let prefix = self.parse_path(PathStyle::Mod)?.default_to_global();
if self.is_import_coupler() {
// `foo::bar::{a, b}` or `foo::bar::*`
self.bump();
}
pub fn path_to_string(p: &ast::Path) -> String {
- to_string(|s| s.print_path(p, false, 0))
+ to_string(|s| s.print_path(p, false, 0, false))
}
pub fn ident_to_string(id: ast::Ident) -> String {
match *vis {
ast::Visibility::Public => format!("pub {}", s),
ast::Visibility::Crate(_) => format!("pub(crate) {}", s),
- ast::Visibility::Restricted { ref path, .. } => format!("pub({}) {}", path, s),
+ ast::Visibility::Restricted { ref path, .. } =>
+ format!("pub({}) {}", to_string(|s| s.print_path(path, false, 0, true)), s),
ast::Visibility::Inherited => s.to_string()
}
}
&generics));
}
ast::TyKind::Path(None, ref path) => {
- try!(self.print_path(path, false, 0));
+ try!(self.print_path(path, false, 0, false));
}
ast::TyKind::Path(Some(ref qself), ref path) => {
try!(self.print_qpath(path, qself, false))
}
ast::ItemKind::Mac(codemap::Spanned { ref node, .. }) => {
try!(self.print_visibility(&item.vis));
- try!(self.print_path(&node.path, false, 0));
+ try!(self.print_path(&node.path, false, 0, false));
try!(word(&mut self.s, "! "));
try!(self.print_ident(item.ident));
try!(self.cbox(INDENT_UNIT));
}
fn print_trait_ref(&mut self, t: &ast::TraitRef) -> io::Result<()> {
- self.print_path(&t.path, false, 0)
+ self.print_path(&t.path, false, 0, false)
}
fn print_formal_lifetime_list(&mut self, lifetimes: &[ast::LifetimeDef]) -> io::Result<()> {
match *vis {
ast::Visibility::Public => self.word_nbsp("pub"),
ast::Visibility::Crate(_) => self.word_nbsp("pub(crate)"),
- ast::Visibility::Restricted { ref path, .. } =>
- self.word_nbsp(&format!("pub({})", path)),
+ ast::Visibility::Restricted { ref path, .. } => {
+ let path = to_string(|s| s.print_path(path, false, 0, true));
+ self.word_nbsp(&format!("pub({})", path))
+ }
ast::Visibility::Inherited => Ok(())
}
}
}
ast::TraitItemKind::Macro(codemap::Spanned { ref node, .. }) => {
// code copied from ItemKind::Mac:
- self.print_path(&node.path, false, 0)?;
+ self.print_path(&node.path, false, 0, false)?;
word(&mut self.s, "! ")?;
self.cbox(INDENT_UNIT)?;
self.popen()?;
}
ast::ImplItemKind::Macro(codemap::Spanned { ref node, .. }) => {
// code copied from ItemKind::Mac:
- try!(self.print_path(&node.path, false, 0));
+ try!(self.print_path(&node.path, false, 0, false));
try!(word(&mut self.s, "! "));
try!(self.cbox(INDENT_UNIT));
try!(self.popen());
pub fn print_mac(&mut self, m: &ast::Mac, delim: token::DelimToken)
-> io::Result<()> {
- try!(self.print_path(&m.node.path, false, 0));
+ try!(self.print_path(&m.node.path, false, 0, false));
try!(word(&mut self.s, "!"));
match delim {
token::Paren => try!(self.popen()),
fields: &[ast::Field],
wth: &Option<P<ast::Expr>>,
attrs: &[Attribute]) -> io::Result<()> {
- try!(self.print_path(path, true, 0));
+ try!(self.print_path(path, true, 0, false));
try!(word(&mut self.s, "{"));
try!(self.print_inner_attributes_inline(attrs));
try!(self.commasep_cmnt(
}
}
ast::ExprKind::Path(None, ref path) => {
- try!(self.print_path(path, true, 0))
+ try!(self.print_path(path, true, 0, false))
}
ast::ExprKind::Path(Some(ref qself), ref path) => {
try!(self.print_qpath(path, qself, true))
fn print_path(&mut self,
path: &ast::Path,
colons_before_params: bool,
- depth: usize)
+ depth: usize,
+ defaults_to_global: bool)
-> io::Result<()>
{
try!(self.maybe_print_comment(path.span.lo));
- let mut first = !path.global;
- for segment in &path.segments[..path.segments.len()-depth] {
- if first {
- first = false
- } else {
+ let mut segments = path.segments[..path.segments.len()-depth].iter();
+ if defaults_to_global && path.is_global() {
+ segments.next();
+ }
+ for (i, segment) in segments.enumerate() {
+ if i > 0 {
try!(word(&mut self.s, "::"))
}
-
- try!(self.print_ident(segment.identifier));
-
- if let Some(ref parameters) = segment.parameters {
- try!(self.print_path_parameters(parameters, colons_before_params))
+ if segment.identifier.name != keywords::CrateRoot.name() &&
+ segment.identifier.name != "$crate" {
+ try!(self.print_ident(segment.identifier));
+ if let Some(ref parameters) = segment.parameters {
+ try!(self.print_path_parameters(parameters, colons_before_params));
+ }
}
}
try!(space(&mut self.s));
try!(self.word_space("as"));
let depth = path.segments.len() - qself.position;
- try!(self.print_path(&path, false, depth));
+ try!(self.print_path(&path, false, depth, false));
}
try!(word(&mut self.s, ">"));
try!(word(&mut self.s, "::"));
}
}
PatKind::TupleStruct(ref path, ref elts, ddpos) => {
- try!(self.print_path(path, true, 0));
+ try!(self.print_path(path, true, 0, false));
try!(self.popen());
if let Some(ddpos) = ddpos {
try!(self.commasep(Inconsistent, &elts[..ddpos], |s, p| s.print_pat(&p)));
try!(self.pclose());
}
PatKind::Path(None, ref path) => {
- try!(self.print_path(path, true, 0));
+ try!(self.print_path(path, true, 0, false));
}
PatKind::Path(Some(ref qself), ref path) => {
try!(self.print_qpath(path, qself, false));
}
PatKind::Struct(ref path, ref fields, etc) => {
- try!(self.print_path(path, true, 0));
+ try!(self.print_path(path, true, 0, false));
try!(self.nbsp());
try!(self.word_space("{"));
try!(self.commasep_cmnt(
try!(self.print_lifetime_bounds(lifetime, bounds));
}
ast::WherePredicate::EqPredicate(ast::WhereEqPredicate{ref path, ref ty, ..}) => {
- try!(self.print_path(path, false, 0));
+ try!(self.print_path(path, false, 0, false));
try!(space(&mut self.s));
try!(self.word_space("="));
try!(self.print_type(&ty));
pub fn print_view_path(&mut self, vp: &ast::ViewPath) -> io::Result<()> {
match vp.node {
ast::ViewPathSimple(ident, ref path) => {
- try!(self.print_path(path, false, 0));
+ try!(self.print_path(path, false, 0, true));
if path.segments.last().unwrap().identifier.name !=
ident.name {
}
ast::ViewPathGlob(ref path) => {
- try!(self.print_path(path, false, 0));
+ try!(self.print_path(path, false, 0, true));
word(&mut self.s, "::*")
}
if path.segments.is_empty() {
try!(word(&mut self.s, "{"));
} else {
- try!(self.print_path(path, false, 0));
+ try!(self.print_path(path, false, 0, true));
try!(word(&mut self.s, "::{"));
}
try!(self.commasep(Inconsistent, &idents[..], |s, w| {
}],
vis: ast::Visibility::Inherited,
node: ast::ItemKind::Use(P(codemap::dummy_spanned(ast::ViewPathGlob(ast::Path {
- global: false,
- segments: vec![name, "prelude", "v1"].into_iter().map(|name| {
+ segments: ["{{root}}", name, "prelude", "v1"].into_iter().map(|name| {
ast::Ident::from_str(name).into()
}).collect(),
span: span,
(53, Default, "default")
(54, StaticLifetime, "'static")
(55, Union, "union")
+
+ // A virtual keyword that resolves to the crate root when used in a lexical scope.
+ (56, CrateRoot, "{{root}}")
}
// If an interner exists in TLS, return it. Otherwise, prepare a fresh one.
fn path_node(ids: Vec<Ident>) -> ast::Path {
ast::Path {
span: DUMMY_SP,
- global: false,
segments: ids.into_iter().map(Into::into).collect(),
}
}
fn path(&self) -> ast::Path {
ast::Path {
span: self.span,
- global: false,
segments: vec![self.ident.into()],
}
}
impl<'a, 'b> visit::Visitor<'a> for Visitor<'a, 'b> {
fn visit_ty(&mut self, ty: &'a ast::Ty) {
- match ty.node {
- ast::TyKind::Path(_, ref path) if !path.global => {
- if let Some(segment) = path.segments.first() {
- if self.ty_param_names.contains(&segment.identifier.name) {
- self.types.push(P(ty.clone()));
- }
+ if let ast::TyKind::Path(_, ref path) = ty.node {
+ if let Some(segment) = path.segments.first() {
+ if self.ty_param_names.contains(&segment.identifier.name) {
+ self.types.push(P(ty.clone()));
}
}
- _ => {}
}
visit::walk_ty(self, ty)
feature_gate::GateIssue::Language,
feature_gate::EXPLAIN_CUSTOM_DERIVE);
} else {
- cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
let name = Symbol::intern(&format!("derive_{}", tname));
+ if !cx.resolver.is_whitelisted_legacy_custom_derive(name) {
+ cx.span_warn(titem.span, feature_gate::EXPLAIN_DEPR_CUSTOM_DERIVE);
+ }
let mitem = cx.meta_word(titem.span, name);
new_attributes.push(cx.attribute(mitem.span, mitem));
}
}
}
+#[cfg(target_os = "redox")]
+fn stdout_isatty() -> bool {
+ // FIXME: Implement isatty on Redox
+ false
+}
#[cfg(unix)]
fn stdout_isatty() -> bool {
unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
}
}
+ #[cfg(target_os = "redox")]
+ fn num_cpus() -> usize {
+ // FIXME: Implement num_cpus on Redox
+ 1
+ }
+
#[cfg(any(target_os = "linux",
target_os = "macos",
target_os = "ios",
return Attribute::UWTable;
case ZExt:
return Attribute::ZExt;
+ case InReg:
+ return Attribute::InReg;
default:
llvm_unreachable("bad AttributeKind");
}
# If this file is modified, then llvm will be forcibly cleaned and then rebuilt.
# The actual contents of this file do not matter, but to trigger a change on the
# build bots then the contents should be changed so git updates the mtime.
-2016-12-16
+2016-12-19
StructRet = 16,
UWTable = 17,
ZExt = 18,
+ InReg = 19,
};
typedef struct OpaqueRustString *RustStringRef;
# tarball for a stable release you'll likely see `1.x.0-$date` where `1.x.0` was
# released on `$date`
-rustc: beta-2016-12-16
-cargo: fbeea902d2c9a5be6d99cc35681565d8f7832592
+rustc: beta-2016-12-20
+cargo: bfee18f73287687c543bda8c35e4e33808792715
--- /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.
+
+// Checks if the "fastcall" calling convention marks function arguments
+// as "inreg" like the C/C++ compilers for the platforms.
+// x86 only.
+
+// ignore-aarch64
+// ignore-aarch64_be
+// ignore-arm
+// ignore-armeb
+// ignore-avr
+// ignore-bpfel
+// ignore-bpfeb
+// ignore-hexagon
+// ignore-mips
+// ignore-mipsel
+// ignore-mips64
+// ignore-mips64el
+// ignore-msp430
+// ignore-powerpc64
+// ignore-powerpc64le
+// ignore-powerpc
+// ignore-r600
+// ignore-amdgcn
+// ignore-sparc
+// ignore-sparcv9
+// ignore-sparcel
+// ignore-s390x
+// ignore-tce
+// ignore-thumb
+// ignore-thumbeb
+// ignore-x86_64 no-ignore-x86
+// ignore-xcore
+// ignore-nvptx
+// ignore-nvptx64
+// ignore-le32
+// ignore-le64
+// ignore-amdil
+// ignore-amdil64
+// ignore-hsail
+// ignore-hsail64
+// ignore-spir
+// ignore-spir64
+// ignore-kalimba
+// ignore-shave
+// ignore-wasm32
+// ignore-wasm64
+
+// compile-flags: -C no-prepopulate-passes
+
+#![crate_type = "lib"]
+
+mod tests {
+ // CHECK: @f1(i32 inreg, i32 inreg, i32)
+ #[no_mangle]
+ extern "fastcall" fn f1(_: i32, _: i32, _: i32) {}
+
+ // CHECK: @f2(i32* inreg, i32* inreg, i32*)
+ #[no_mangle]
+ extern "fastcall" fn f2(_: *const i32, _: *const i32, _: *const i32) {}
+
+ // CHECK: @f3(float, i32 inreg, i32 inreg, i32)
+ #[no_mangle]
+ extern "fastcall" fn f3(_: f32, _: i32, _: i32, _: i32) {}
+
+ // CHECK: @f4(i32 inreg, float, i32 inreg, i32)
+ #[no_mangle]
+ extern "fastcall" fn f4(_: i32, _: f32, _: i32, _: i32) {}
+
+ // CHECK: @f5(i64, i32)
+ #[no_mangle]
+ extern "fastcall" fn f5(_: i64, _: i32) {}
+
+ // CHECK: @f6(i1 inreg zeroext, i32 inreg, i32)
+ #[no_mangle]
+ extern "fastcall" fn f6(_: bool, _: i32, _: i32) {}
+}
extern crate macro_crate_test;
fn main() {
- macro_crate_test::foo(); //~ ERROR unresolved name
+ macro_crate_test::foo(); //~ ERROR unresolved function `macro_crate_test::foo`
}
assert_eq!(pprust::expr_to_string(&*quote_expr!(&cx, 23)), "23");
- let expr = quote_expr!(&cx, 2 - $abcd + 7); //~ ERROR unresolved name `abcd`
+ let expr = quote_expr!(&cx, 2 - $abcd + 7); //~ ERROR unresolved value `abcd`
assert_eq!(pprust::expr_to_string(&*expr), "2 - $abcd + 7");
}
fn main() {
let trait_obj: &SomeTrait = SomeTrait;
- //~^ ERROR E0425
- //~| NOTE unresolved name
+ //~^ ERROR expected value, found trait `SomeTrait`
+ //~| NOTE not a value
//~| ERROR E0038
//~| method `foo` has no receiver
//~| NOTE the trait `SomeTrait` cannot be made into an object
+++ /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 {
- Bar(u32),
-}
-
-fn do_something(x: Foo::Bar) { } //~ ERROR E0248
- //~| NOTE value used as a type
-fn main() {
-}
struct Foo { a: bool };
let f = Foo(); //~ ERROR E0423
- //~^ struct called like a function
}
fn bar(self) {}
fn foo() {
- self.bar();
- //~^ ERROR `self` is not available in a static method [E0424]
- //~| NOTE not available in static method
- //~| NOTE maybe a `self` argument is missing?
+ self.bar(); //~ ERROR E0424
}
}
trait Foo {
fn bar() {
- Self; //~ ERROR E0425
+ elf; //~ ERROR E0425
}
}
+++ /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 std::mem;
-
-fn main() {
- unsafe {
- let size = mem::size_of::<u32>();
- mem::transmute_copy::<u32, [u8; size]>(&8_8); //~ ERROR E0513
- //~| NOTE no type for variable
- }
-}
}
pub fn test<A: Foo, B: Foo>() {
- let _array = [4; <A as Foo>::Y]; //~ ERROR E0080
- //~| non-constant path in constant
+ 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 the trait bound `A: Foo` is not satisfied
+ //~^ ERROR cannot use an outer type parameter in this context [E0402]
+ //~| ERROR constant evaluation error [E0080]
+ //~| non-constant path in constant
}
fn main() {
// Check that associated paths starting with `<<` are successfully parsed.
fn main() {
- let _: <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
- let _ = <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
- let <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
- let 0 ... <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
+ let _: <<A>::B>::C; //~ ERROR unresolved type `A`
+ let _ = <<A>::B>::C; //~ ERROR unresolved type `A`
+ let <<A>::B>::C; //~ ERROR unresolved type `A`
+ let 0 ... <<A>::B>::C; //~ ERROR unresolved type `A`
//~^ ERROR only char and numeric types are allowed in range patterns
- <<A>::B>::C; //~ ERROR type name `A` is undefined or not in scope
+ <<A>::B>::C; //~ ERROR unresolved type `A`
}
}
fn foo2<I: Foo>(x: I) {
- let _: A = x.boo(); //~ERROR undefined or not in scope
+ let _: A = x.boo(); //~ ERROR unresolved type `A`
}
pub 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.
-
-// testing whether the lookup mechanism picks up types
-// defined in the outside crate
-
-#![crate_type="lib"]
-
-pub mod outer {
- // should suggest this
- pub trait OuterTrait {}
-
- // should not suggest this since the module is private
- mod private_module {
- pub trait OuterTrait {}
- }
-
- // should not suggest since the trait is private
- pub mod public_module {
- trait OuterTrait {}
- }
-}
+++ /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.
-
-// testing whether the lookup mechanism picks up types
-// defined in the outside crate
-
-#![crate_type="lib"]
-
-mod foo {
- // should not be suggested => foo is private
- pub trait T {}
-}
-
-// should be suggested
-pub use foo::T;
+++ /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.
-
-pub enum Homura {
- Madoka { age: u32 }
-}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-pub trait Foo {
- fn bar();
-}
pub struct StableStruct {
#[stable(feature = "test_feature", since = "1.0.0")] pub i: isize
}
+#[unstable(feature = "test_feature", issue = "0")]
+pub enum UnstableEnum {}
+#[stable(feature = "rust1", since = "1.0.0")]
+pub enum StableEnum {}
#[stable(feature = "test_feature", since = "1.0.0")]
#[rustc_deprecated(since = "1.0.0", reason = "text")]
// except according to those terms.
// no-prefer-dynamic
+// compile-flags: --emit=metadata
-#![crate_type="metadata"]
+#![crate_type="rlib"]
pub struct Foo {
pub field: i32,
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unresolved name `m1::arguments`
-
mod m1 {}
-fn main(arguments: Vec<String>) { log(debug, m1::arguments); }
+fn main(arguments: Vec<String>) { //~ ERROR main function has wrong type
+ log(debug, m1::arguments);
+ //~^ ERROR unresolved function `log`
+ //~| ERROR unresolved value `debug`
+ //~| ERROR unresolved value `m1::arguments`
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unresolved name `m1::arguments`
-
mod m1 {
pub mod arguments {}
}
-fn main(arguments: Vec<String>) {
+fn main(arguments: Vec<String>) { //~ ERROR main function has wrong type
log(debug, m1::arguments);
+ //~^ ERROR unresolved function `log`
+ //~| ERROR unresolved value `debug`
+ //~| ERROR expected value, found module `m1::arguments`
}
fn sleep(&self) { loop{} }
fn meow(&self) {
println!("Meow");
- meows += 1; //~ ERROR unresolved name
- sleep(); //~ ERROR unresolved name
+ meows += 1; //~ ERROR unresolved value `meows`
+ sleep(); //~ ERROR unresolved function `sleep`
}
}
impl Foo for i16 {}
impl Foo for i32 {}
impl Foo for i64 {}
-impl Foo for DoesNotExist {} //~ ERROR `DoesNotExist` is undefined
+impl Foo for DoesNotExist {} //~ ERROR unresolved type `DoesNotExist`
impl Foo for u8 {}
impl Foo for u16 {}
impl Foo for u32 {}
mod signatures {
use WillChange;
- #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
- #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK
+ #[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
+ #[rustc_then_this_would_need(CollectItem)] //~ ERROR no path
trait Bar {
+ #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
+ #[rustc_then_this_would_need(CollectItem)] //~ ERROR OK
fn do_something(x: WillChange);
}
Variant2(i32)
}
-#[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
+#[rustc_then_this_would_need(ItemSignature)] //~ ERROR no path
trait Trait {
+ #[rustc_then_this_would_need(ItemSignature)] //~ ERROR OK
fn method(&self, _: TypeAlias);
}
}
fn foo() -> Result<(), ()> {
- try!(closure(|| bar(0 as *mut _))); //~ ERROR unresolved name `bar`
+ try!(closure(|| bar(0 as *mut _))); //~ ERROR unresolved function `bar`
Ok(())
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unresolved name `this_does_nothing_what_the`
fn main() { println!("doing"); this_does_nothing_what_the; println!("boing"); }
+//~^ ERROR unresolved value `this_does_nothing_what_the`
}
fn main() {
- let e1 = Empty1; //~ ERROR `Empty1` is the name of a struct or struct variant
- let e1 = Empty1(); //~ ERROR `Empty1` is the name of a struct or struct variant
- let e3 = E::Empty3; //~ ERROR `E::Empty3` is the name of a struct or struct variant
- let e3 = E::Empty3(); //~ ERROR `E::Empty3` is the name of a struct or struct variant
+ let e1 = Empty1; //~ ERROR expected value, found struct `Empty1`
+ let e1 = Empty1(); //~ ERROR expected function, found struct `Empty1`
+ let e3 = E::Empty3; //~ ERROR expected value, found struct variant `E::Empty3`
+ let e3 = E::Empty3(); //~ ERROR expected function, found struct variant `E::Empty3`
- let xe1 = XEmpty1; //~ ERROR `XEmpty1` is the name of a struct or struct variant
- let xe1 = XEmpty1(); //~ ERROR `XEmpty1` is the name of a struct or struct variant
+ let xe1 = XEmpty1; //~ ERROR expected value, found struct `XEmpty1`
+ let xe1 = XEmpty1(); //~ ERROR expected function, found struct `XEmpty1`
let xe3 = XE::Empty3; //~ ERROR no associated item named `Empty3` found for type
let xe3 = XE::Empty3(); //~ ERROR no associated item named `Empty3` found for type
}
let xe1 = XEmpty1 {};
match e1 {
- Empty1() => () //~ ERROR unresolved tuple struct/variant `Empty1`
+ Empty1() => () //~ ERROR expected tuple struct/variant, found struct `Empty1`
}
match xe1 {
- XEmpty1() => () //~ ERROR unresolved tuple struct/variant `XEmpty1`
+ XEmpty1() => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1`
}
match e1 {
- Empty1(..) => () //~ ERROR unresolved tuple struct/variant `Empty1`
+ Empty1(..) => () //~ ERROR expected tuple struct/variant, found struct `Empty1`
}
match xe1 {
- XEmpty1(..) => () //~ ERROR unresolved tuple struct/variant `XEmpty1`
+ XEmpty1(..) => () //~ ERROR expected tuple struct/variant, found struct `XEmpty1`
}
}
Bar
}
-fn foo(x: Foo::Bar) {} //~ERROR found value `Foo::Bar` used as a type
+fn foo(x: Foo::Bar) {} //~ ERROR expected type, found variant `Foo::Bar`
fn main() {}
+++ /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.
-
-// aux-build:namespaced_enums.rs
-extern crate namespaced_enums;
-
-fn main() {
- let _ = namespaced_enums::A; //~ ERROR unresolved name
- let _ = namespaced_enums::B(10); //~ ERROR unresolved name
- let _ = namespaced_enums::C { a: 10 };
- //~^ ERROR unresolved struct, variant or union type `namespaced_enums::C`
-}
}
impl<'a,'b> Foo<'a,'b> {
- fn bar(
- self
+ fn bar(self:
+ Foo<'b,'a>
//~^ ERROR mismatched method receiver
//~| expected type `Foo<'a, 'b>`
//~| found type `Foo<'b, 'a>`
//~| expected type `Foo<'a, 'b>`
//~| found type `Foo<'b, 'a>`
//~| lifetime mismatch
- : Foo<'b,'a>) {}
+ ) {}
}
fn main() {}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: failed to resolve. Use of undeclared type or module `foo`
-
// In this test baz isn't resolved when called as foo.baz even though
// it's called from inside foo. This is somewhat surprising and may
// want to change eventually.
mod foo {
- pub fn bar() { foo::baz(); }
+ pub fn bar() { foo::baz(); } //~ ERROR failed to resolve. Use of undeclared type or module `foo`
fn baz() { }
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unresolved name
mod foo {
pub fn x(y: isize) { log(debug, y); }
+ //~^ ERROR unresolved function `log`
+ //~| ERROR unresolved value `debug`
fn z(y: isize) { log(debug, y); }
+ //~^ ERROR unresolved function `log`
+ //~| ERROR unresolved value `debug`
}
-fn main() { foo::z(10); }
+fn main() { foo::z(10); } //~ ERROR function `z` is private
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: failed to resolve. Use of undeclared type or module `bar`
-
mod foo {
- pub fn x() { bar::x(); }
+ pub fn x() { bar::x(); } //~ ERROR failed to resolve. Use of undeclared type or module `bar`
}
mod bar {
// Unresolved bounds should still error.
fn align_of<T: NoSuchTrait>() -> usize;
- //~^ ERROR trait `NoSuchTrait` is not in scope
+ //~^ ERROR unresolved trait `NoSuchTrait`
}
fn main() {}
fn main() {
// Odd formatting to make sure we get the right span.
for t in &
- foo //~ ERROR unresolved name `foo`
+ foo //~ ERROR unresolved value `foo`
{
}
}
fn main() {
for _ in 0..10 {
- iter.next(); //~ error: unresolved name `iter`
+ iter.next(); //~ ERROR unresolved value `iter`
}
}
fn foo<T>() {}
fn main() {
- fpriv(); //~ ERROR: unresolved
- epriv(); //~ ERROR: unresolved
- B; //~ ERROR: unresolved
- C; //~ ERROR: unresolved
- import(); //~ ERROR: unresolved
-
- foo::<A>(); //~ ERROR: not in scope
- foo::<C>(); //~ ERROR: not in scope
- foo::<D>(); //~ ERROR: not in scope
+ fpriv(); //~ ERROR unresolved function `fpriv`
+ epriv(); //~ ERROR unresolved function `epriv`
+ B; //~ ERROR expected value, found enum `B`
+ C; //~ ERROR unresolved value `C`
+ import(); //~ ERROR: unresolved function `import`
+
+ foo::<A>(); //~ ERROR: unresolved type `A`
+ foo::<C>(); //~ ERROR: unresolved type `C`
+ foo::<D>(); //~ ERROR: unresolved type `D`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unresolved name
-
use module_of_many_things::*;
mod module_of_many_things {
fn main() {
f1();
f2();
- f999(); // 'export' currently doesn't work?
+ f999(); //~ ERROR unresolved function `f999`
f4();
}
+++ /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.
-
-trait Foo {
- fn bar(&self);
- fn baz(&self) { }
- fn bah(_: Option<&Self>) { }
-}
-
-struct BarTy {
- x : isize,
- y : f64,
-}
-
-impl BarTy {
- fn a() {}
- fn b(&self) {}
-}
-
-impl Foo for *const BarTy {
- fn bar(&self) {
- baz();
- //~^ ERROR: unresolved name `baz`
- //~| NOTE did you mean to call `self.baz`?
- a;
- //~^ ERROR: unresolved name `a`
- //~| NOTE unresolved name
- }
-}
-
-impl<'a> Foo for &'a BarTy {
- fn bar(&self) {
- baz();
- //~^ ERROR: unresolved name `baz`
- //~| NOTE did you mean to call `self.baz`?
- x;
- //~^ ERROR: unresolved name `x`
- //~| NOTE did you mean `self.x`?
- y;
- //~^ ERROR: unresolved name `y`
- //~| NOTE did you mean `self.y`?
- a;
- //~^ ERROR: unresolved name `a`
- //~| NOTE unresolved name
- bah;
- //~^ ERROR: unresolved name `bah`
- //~| NOTE did you mean to call `Foo::bah`?
- b;
- //~^ ERROR: unresolved name `b`
- //~| NOTE unresolved name
- }
-}
-
-impl<'a> Foo for &'a mut BarTy {
- fn bar(&self) {
- baz();
- //~^ ERROR: unresolved name `baz`
- //~| NOTE did you mean to call `self.baz`?
- x;
- //~^ ERROR: unresolved name `x`
- //~| NOTE did you mean `self.x`?
- y;
- //~^ ERROR: unresolved name `y`
- //~| NOTE did you mean `self.y`?
- a;
- //~^ ERROR: unresolved name `a`
- //~| NOTE unresolved name
- bah;
- //~^ ERROR: unresolved name `bah`
- //~| NOTE did you mean to call `Foo::bah`?
- b;
- //~^ ERROR: unresolved name `b`
- //~| NOTE unresolved name
- }
-}
-
-impl Foo for Box<BarTy> {
- fn bar(&self) {
- baz();
- //~^ ERROR: unresolved name `baz`
- //~| NOTE did you mean to call `self.baz`?
- bah;
- //~^ ERROR: unresolved name `bah`
- //~| NOTE did you mean to call `Foo::bah`?
- }
-}
-
-impl Foo for *const isize {
- fn bar(&self) {
- baz();
- //~^ ERROR: unresolved name `baz`
- //~| NOTE did you mean to call `self.baz`?
- bah;
- //~^ ERROR: unresolved name `bah`
- //~| NOTE did you mean to call `Foo::bah`?
- }
-}
-
-impl<'a> Foo for &'a isize {
- fn bar(&self) {
- baz();
- //~^ ERROR: unresolved name `baz`
- //~| NOTE did you mean to call `self.baz`?
- bah;
- //~^ ERROR: unresolved name `bah`
- //~| NOTE did you mean to call `Foo::bah`?
- }
-}
-
-impl<'a> Foo for &'a mut isize {
- fn bar(&self) {
- baz();
- //~^ ERROR: unresolved name `baz`
- //~| NOTE did you mean to call `self.baz`?
- bah;
- //~^ ERROR: unresolved name `bah`
- //~| NOTE did you mean to call `Foo::bah`?
- }
-}
-
-impl Foo for Box<isize> {
- fn bar(&self) {
- baz();
- //~^ ERROR: unresolved name `baz`
- //~| NOTE did you mean to call `self.baz`?
- bah;
- //~^ ERROR: unresolved name `bah`
- //~| NOTE did you mean to call `Foo::bah`?
- }
-}
// except according to those terms.
fn main() {
- println!("{}", x); //~ ERROR unresolved name `x`
+ println!("{}", x); //~ ERROR unresolved value `x`
}
// macro f should not be able to inject a reference to 'n'.
macro_rules! f { () => (n) }
-//~^ ERROR unresolved name `n`
-//~| ERROR unresolved name `n`
-//~| ERROR unresolved name `n`
-//~| ERROR unresolved name `n`
+//~^ ERROR unresolved value `n`
+//~| ERROR unresolved value `n`
+//~| ERROR unresolved value `n`
+//~| ERROR unresolved value `n`
fn main() -> (){
for n in 0..1 {
+++ /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.
-
-
-pub struct GslResult {
- pub val: f64,
- pub err: f64
-}
-
-impl GslResult {
- pub fn new() -> GslResult {
- Result { //~ ERROR: expected struct, variant or union type, found enum `Result`
- val: 0f64,
- err: 0f64
- }
- }
-}
-
-fn main() {}
+++ /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.
-
-enum SomeEnum {
- E
-}
-
-fn main() {
- E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
-}
}
fn new() -> NoResult<MyEnum, String> {
- //~^ ERROR: found value `foo::MyEnum::NoResult` used as a type
+ //~^ ERROR expected type, found variant `NoResult`
unimplemented!()
}
}
use foo;
fn new() -> Result<foo::MyEnum, String> {
- //~^ ERROR: found value `foo::MyEnum::Result` used as a type
+ //~^ ERROR expected type, found variant `Result`
unimplemented!()
}
}
fn new() -> Result<foo::MyEnum, String> {
- //~^ ERROR: found value `foo::MyEnum::Result` used as a type
+ //~^ ERROR expected type, found variant `Result`
unimplemented!()
}
fn newer() -> NoResult<foo::MyEnum, String> {
- //~^ ERROR: found value `foo::MyEnum::NoResult` used as a type
+ //~^ ERROR expected type, found variant `NoResult`
unimplemented!()
}
// except according to those terms.
impl Undefined {}
-//~^ ERROR type name `Undefined` is undefined or not in scope
+//~^ ERROR unresolved type `Undefined`
fn main() {}
fn foo() {}
impl X {}
-//~^ ERROR type name `X` is undefined or not in scope
+//~^ ERROR expected type, found constant `X`
impl Y {}
-//~^ ERROR type name `Y` is undefined or not in scope
+//~^ ERROR expected type, found static `Y`
impl foo {}
-//~^ ERROR type name `foo` is undefined or not in scope
+//~^ ERROR expected type, found function `foo`
fn main() {}
+++ /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.
-
-enum Foo {
- Variant { x: usize }
-}
-
-fn main() {
- let f = Foo::Variant(42);
- //~^ ERROR uses it like a function
- //~| struct called like a function
-}
+++ /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.
-
-// aux-build:issue_19452_aux.rs
-extern crate issue_19452_aux;
-
-enum Homura {
- Madoka { age: u32 }
-}
-
-fn main() {
- let homura = Homura::Madoka;
- //~^ ERROR uses it like a function
- //~| struct called like a function
-
- let homura = issue_19452_aux::Homura::Madoka;
- //~^ ERROR uses it like a function
- //~| struct called like a function
-}
trait To: Sized {
fn to<Dst: From<Self>>(self) ->
<Dst as From<Self>>::Dst
- //~^ ERROR associated type `From::Dst` is undefined or not in scope
+ //~^ ERROR unresolved associated type `From::Dst`
{
From::from(self)
}
+++ /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.
-
-mod mul1 {
- pub trait Mul {}
-}
-
-mod mul2 {
- pub trait Mul {}
-}
-
-mod mul3 {
- enum Mul {
- Yes,
- No
- }
-}
-
-mod mul4 {
- type Mul = String;
-}
-
-mod mul5 {
- struct Mul{
- left_term: u32,
- right_term: u32
- }
-}
-
-#[derive(Debug)]
-struct Foo;
-
-// When we comment the next line:
-//use mul1::Mul;
-
-// BEFORE, we got the following error for the `impl` below:
-// error: use of undeclared trait name `Mul` [E0405]
-// AFTER, we get this message:
-// error: trait `Mul` is not in scope.
-// help: ...
-// help: you can import several candidates into scope (`use ...;`):
-// help: `mul1::Mul`
-// help: `mul2::Mul`
-// help: `std::ops::Mul`
-
-impl Mul for Foo {
-//~^ ERROR trait `Mul` is not in scope
-//~| HELP `mul1::Mul`
-//~| HELP `mul2::Mul`
-//~| HELP `std::ops::Mul`
-//~| HELP you can import several candidates into scope (`use ...;`):
-}
-
-// BEFORE, we got:
-// error: use of undeclared type name `Mul` [E0412]
-// AFTER, we get:
-// error: type name `Mul` is not in scope. Maybe you meant:
-// help: ...
-// help: you can import several candidates into scope (`use ...;`):
-// help: `mul1::Mul`
-// help: `mul2::Mul`
-// help: `mul3::Mul`
-// help: `mul4::Mul`
-// help: and 2 other candidates
-fn getMul() -> Mul {
-//~^ ERROR type name `Mul` is undefined or not in scope
-//~| HELP `mul1::Mul`
-//~| HELP `mul2::Mul`
-//~| HELP `mul3::Mul`
-//~| HELP `mul4::Mul`
-//~| HELP and 2 other candidates
-//~| HELP you can import several candidates into scope (`use ...;`):
-}
-
-// Let's also test what happens if the trait doesn't exist:
-impl ThisTraitReallyDoesntExistInAnyModuleReally for Foo {
-//~^ ERROR trait `ThisTraitReallyDoesntExistInAnyModuleReally` is not in scope
-//~| HELP no candidates by the name of `ThisTraitReallyDoesntExistInAnyModuleReally` found
-}
-
-// Let's also test what happens if there's just one alternative:
-impl Div for Foo {
-//~^ ERROR trait `Div` is not in scope
-//~| HELP `use std::ops::Div;`
-}
-
-fn main() {
- let foo = Foo();
- println!("Hello, {:?}!", foo);
-}
+++ /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.
-
-pub mod foo {
- pub mod bar {
- // note: trait T is not public, but being in the current
- // crate, it's fine to show it, since the programmer can
- // decide to make it public based on the suggestion ...
- pub trait T {}
- }
- // imports should be ignored:
- use self::bar::T;
-}
-
-pub mod baz {
- pub use foo;
- pub use std::ops::{Mul as T};
-}
-
-struct Foo;
-impl T for Foo { }
-//~^ ERROR trait `T` is not in scope
-//~| HELP you can import it into scope: `use foo::bar::T;`.
+++ /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.
-
-// testing whether the lookup mechanism picks up types
-// defined in the outside crate
-
-// aux-build:issue-21221-3.rs
-
-extern crate issue_21221_3;
-
-struct Foo;
-
-// NOTE: This shows only traits accessible from the current
-// crate, thus the two private entities:
-// `issue_21221_3::outer::private_module::OuterTrait` and
-// `issue_21221_3::outer::public_module::OuterTrait`
-// are hidden from the view.
-impl OuterTrait for Foo {}
-//~^ ERROR trait `OuterTrait` is not in scope
-//~| HELP you can import it into scope: `use issue_21221_3::outer::OuterTrait;`.
-fn main() {
- println!("Hello, world!");
-}
+++ /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.
-
-// testing whether the lookup mechanism picks up types
-// defined in the outside crate
-
-// aux-build:issue-21221-4.rs
-
-extern crate issue_21221_4;
-
-struct Foo;
-
-impl T for Foo {}
-//~^ ERROR trait `T` is not in scope
-//~| HELP you can import it into scope: `use issue_21221_4::T;`.
-
-fn main() {
- println!("Hello, world!");
-}
trait A {
type Output;
fn a(&self) -> <Self as A>::X;
-//~^ ERROR: associated type `A::X` is undefined or not in scope
+ //~^ ERROR unresolved associated type `A::X`
}
impl A for u32 {
fn main() {
<<i32 as Copy>::foobar as Trait>::foo();
- //~^ ERROR associated type `Copy::foobar` is undefined or not in scope
+ //~^ ERROR unresolved associated type `Copy::foobar`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-// error-pattern: unresolved name `foobar`
-
-fn main() { println!("{}", foobar); }
+fn main() { println!("{}", foobar); } //~ ERROR unresolved value `foobar`
}
// `chan` is not a trait, it's an enum
-impl chan for isize { //~ ERROR `chan` is not a trait
+impl chan for isize { //~ ERROR expected trait, found enum `chan`
fn send(&self, v: isize) { panic!() }
}
+++ /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.
-
-pub trait ToNbt<T> {
- fn new(val: T) -> Self;
-}
-
-impl ToNbt<Self> {} //~ ERROR use of `Self` outside of an impl or trait
-//~^ ERROR the trait `ToNbt` cannot be made into an object
-
-fn main() {}
+++ /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.
-
-trait Groom {
- fn shave(other: usize);
-}
-
-pub struct cat {
- whiskers: isize,
-}
-
-pub enum MaybeDog {
- Dog,
- NoDog
-}
-
-impl MaybeDog {
- fn bark() {
- // If this provides a suggestion, it's a bug as MaybeDog doesn't impl Groom
- shave();
- //~^ ERROR: unresolved name `shave`
- //~| NOTE unresolved name
- }
-}
-
-impl Groom for cat {
- fn shave(other: usize) {
- whiskers -= other;
- //~^ ERROR: unresolved name `whiskers`
- //~| NOTE unresolved name
- //~| HELP this is an associated function
- shave(4);
- //~^ ERROR: unresolved name `shave`
- //~| NOTE did you mean to call `Groom::shave`?
- purr();
- //~^ ERROR: unresolved name `purr`
- //~| NOTE unresolved name
- }
-}
-
-impl cat {
- fn static_method() {}
-
- fn purr_louder() {
- static_method();
- //~^ ERROR: unresolved name `static_method`
- //~| NOTE unresolved name
- purr();
- //~^ ERROR: unresolved name `purr`
- //~| NOTE unresolved name
- purr();
- //~^ ERROR: unresolved name `purr`
- //~| NOTE unresolved name
- purr();
- //~^ ERROR: unresolved name `purr`
- //~| NOTE unresolved name
- }
-}
-
-impl cat {
- fn meow() {
- if self.whiskers > 3 {
- //~^ ERROR `self` is not available in a static method [E0424]
- //~| NOTE not available in static method
- //~| NOTE maybe a `self` argument is missing?
- println!("MEOW");
- }
- }
-
- fn purr(&self) {
- grow_older();
- //~^ ERROR: unresolved name `grow_older`
- //~| NOTE unresolved name
- shave();
- //~^ ERROR: unresolved name `shave`
- //~| NOTE unresolved name
- }
-
- fn burn_whiskers(&mut self) {
- whiskers = 0;
- //~^ ERROR: unresolved name `whiskers`
- //~| NOTE did you mean `self.whiskers`?
- }
-
- pub fn grow_older(other:usize) {
- whiskers = 4;
- //~^ ERROR: unresolved name `whiskers`
- //~| NOTE unresolved name
- //~| HELP this is an associated function
- purr_louder();
- //~^ ERROR: unresolved name `purr_louder`
- //~| NOTE unresolved name
- }
-}
-
-fn main() {
- self += 1;
- //~^ ERROR: unresolved name `self`
- //~| NOTE unresolved name
- //~| HELP: module `self`
- // it's a bug if this suggests a missing `self` as we're not in a method
-}
+++ /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.
-
-fn foo(_: Self) {
- //~^ ERROR use of `Self` outside of an impl or trait
-}
-
-fn main() {}
//~| expected type `usize`
//~| found type `S`
//~| expected usize, found struct `S`
- //~| ERROR expected `usize` for repeat count, found struct [E0306]
- //~| expected `usize`
}
// Prefix in imports with empty braces should be resolved and checked privacy, stability, etc.
-use foo::{};
-//~^ ERROR failed to resolve. Maybe a missing `extern crate foo;`?
-//~| NOTE foo
+use foo::{}; //~ ERROR unresolved module or enum `foo`
fn main() {}
extern crate lint_stability;
-use lint_stability::UnstableStruct::{};
-//~^ ERROR use of unstable library feature 'test_feature'
-use lint_stability::StableStruct::{}; // OK
+use lint_stability::UnstableEnum::{}; //~ ERROR use of unstable library feature 'test_feature'
+use lint_stability::StableEnum::{}; // OK
fn main() {}
extern crate issue_30535 as foo;
fn bar(
- _: foo::Foo::FooV //~ ERROR value `foo::Foo::FooV` used as a type
+ _: foo::Foo::FooV //~ ERROR expected type, found variant `foo::Foo::FooV`
) {}
fn main() {}
use std::fmt;
-impl fmt::Display for DecoderError { //~ ERROR E0412
+impl fmt::Display for DecoderError { //~ ERROR unresolved type `DecoderError`
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Missing data: {}", self.0)
}
fn g() {}
mod foo {
fn h() {
- g(); //~ ERROR unresolved name
+ g(); //~ ERROR unresolved function `g`
}
}
}
+++ /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 std::any::Any;
-
-struct Foo;
-
-trait Bar {}
-
-impl Bar for Foo {}
-
-fn main() {
- let any: &Any = &Bar; //~ ERROR E0425
- //~| HELP trait `Bar`
- if any.is::<u32>() { println!("u32"); }
-}
fn main () {
let sr: Vec<(u32, _, _) = vec![]; //~ ERROR expected one of `+`, `,`, or `>`, found `=`
let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect();
- //~^ ERROR unresolved name `sr`
+ //~^ ERROR unresolved value `sr`
}
// except according to those terms.
struct Bar<T> {
- inner: Foo<T> //~ ERROR type name `Foo` is undefined or not in scope
+ inner: Foo<T> //~ ERROR unresolved type `Foo`
}
enum Baz<T> {
- Foo(Foo<T>) //~ ERROR type name `Foo` is undefined or not in scope
+ Foo(Foo<T>) //~ ERROR unresolved type `Foo`
}
fn main() {}
// except according to those terms.
struct Foo<T: ?Hash> { }
-//~^ ERROR trait `Hash` is not in scope [E0405]
-//~^^ ERROR parameter `T` is never used [E0392]
+//~^ ERROR unresolved trait `Hash`
+//~^^ ERROR parameter `T` is never used
//~^^^ WARN default bound relaxed for a type parameter, but this does nothing
fn main() { }
+++ /dev/null
-// Copyright 2013-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.
-
-// aux-build:issue_3907.rs
-extern crate issue_3907;
-
-type Foo = issue_3907::Foo+'static;
-
-struct S {
- name: isize
-}
-
-fn bar(_x: Foo) {}
-//~^ ERROR E0038
-
-fn main() {}
+++ /dev/null
-// Copyright 2013-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.
-
-// aux-build:issue_3907.rs
-extern crate issue_3907;
-
-type Foo = issue_3907::Foo;
-
-struct S {
- name: isize
-}
-
-impl Foo for S { //~ ERROR: `Foo` is not a trait
- //~| NOTE: expected trait, found type alias
- //~| NOTE: type aliases cannot be used for traits
- fn bar() { }
-}
-
-fn main() {
- let s = S {
- name: 0
- };
- s.bar();
-}
pub mod sub {
use a::b::*;
fn sub() -> bar { 1 }
- //~^ ERROR: type name `bar` is undefined or not in scope
+ //~^ ERROR unresolved type `bar`
}
}
}
fn main() {
- foo(); //~ ERROR: unresolved name
+ foo(); //~ ERROR expected function, found module `foo`
}
}
pub mod sub {
use a::b::*;
- fn sub() -> isize { foo(); 1 } //~ ERROR: unresolved name `foo`
+ fn sub() -> isize { foo(); 1 } //~ ERROR unresolved function `foo`
}
}
+++ /dev/null
-// Copyright 2013-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.
-
-trait I {}
-type K = I+'static;
-
-fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied
-
-fn main() {}
+++ /dev/null
-// Copyright 2013-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.
-
-trait I {}
-type K = I;
-impl K for isize {} //~ ERROR: `K` is not a trait
- //~| NOTE: expected trait, found type alias
- //~| NOTE: aliases cannot be used for traits
-
-use ImportError; //~ ERROR unresolved import `ImportError` [E0432]
- //~^ no `ImportError` in the root
-impl ImportError for () {} // check that this is not an additional error (c.f. #35142)
-
-fn main() {}
// except according to those terms.
-trait B < A > { fn a() -> A { this.a } } //~ ERROR unresolved name
+trait B < A > { fn a() -> A { this.a } } //~ ERROR unresolved value `this`
fn main() {}
fn main() {
let z = match 3 {
x(1) => x(1) //~ ERROR unresolved tuple struct/variant `x`
- //~^ ERROR unresolved name `x`
+ //~^ ERROR unresolved function `x`
};
assert!(z == 3);
}
+++ /dev/null
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-struct Monster {
- damage: isize
-}
-
-
-fn main() {
- let _m = Monster(); //~ ERROR `Monster` is the name of a struct or
- //~^ HELP did you mean to write: `Monster { /* fields */ }`?
-}
x: isize
}
-impl Fo { //~ ERROR type name `Fo` is undefined or not in scope
+impl Fo { //~ ERROR unresolved type `Fo`
fn foo() {}
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-impl B { //~ ERROR type name `B` is undefined or not in scope
+impl B { //~ ERROR unresolved type `B`
}
fn main() {
// except according to those terms.
fn main() {
- let super = "foo"; //~ ERROR unresolved unit struct/variant or constant `super`
+ let super = "foo"; //~ ERROR failed to resolve. There are too many initial `super`s
}
// except according to those terms.
fn main() {
- let super: isize; //~ ERROR unresolved unit struct/variant or constant `super`
+ let super: isize; //~ ERROR failed to resolve. There are too many initial `super`s
}
// test1!(#[bar])
#[qux]
fn main() {
- a::bar(); //~ ERROR unresolved name `a::bar`
+ a::bar(); //~ ERROR unresolved function `a::bar`
b::bar();
}
// not to the macro variable '$id'
fn main() {
foo!(
- x //~ ERROR unresolved name `x`
+ x //~ ERROR unresolved value `x`
);
}
fn main() {
match true { false => { my_panic(); } true => { } }
- println!("{}", x); //~ ERROR unresolved name `x`
+ println!("{}", x); //~ ERROR unresolved value `x`
let x: isize;
}
[0, 1, 2, 3, x..] => {} //~ ERROR pattern requires
};
- match does_not_exist { //~ ERROR unresolved name
+ match does_not_exist { //~ ERROR unresolved value `does_not_exist`
[] => {}
};
}
mod mod_file_aux;
fn main() {
- assert!(mod_file_aux::bar() == 10); //~ ERROR unresolved name
+ assert!(mod_file_aux::bar() == 10); //~ ERROR unresolved function `mod_file_aux::bar`
}
fn main() {
let None: isize = 42; //~ ERROR let bindings cannot shadow unit variants
log(debug, None);
- //~^ ERROR unresolved name `debug`
- //~| ERROR unresolved name `log`
+ //~^ ERROR unresolved function `log`
+ //~| ERROR unresolved value `debug`
}
fn f12() {
check(m1::S{}); //~ ERROR c::Item
- check(m1::S); //~ ERROR unresolved name
+ check(m1::S); //~ ERROR expected value, found type alias `m1::S`
check(m2::S{}); //~ ERROR c::S
check(m2::S); //~ ERROR c::Item
}
fn xf12() {
check(xm1::S{}); //~ ERROR c::Item
- check(xm1::S); //~ ERROR unresolved name
+ check(xm1::S); //~ ERROR expected value, found type alias `xm1::S`
check(xm2::S{}); //~ ERROR c::S
check(xm2::S); //~ ERROR c::Item
}
fn f78() {
check(m7::V{}); //~ ERROR c::Item
- check(m7::V); //~ ERROR name of a struct or struct variant
+ check(m7::V); //~ ERROR expected value, found struct variant `m7::V`
check(m8::V{}); //~ ERROR c::E
check(m8::V); //~ ERROR c::Item
}
fn xf78() {
check(xm7::V{}); //~ ERROR c::Item
- check(xm7::V); //~ ERROR name of a struct or struct variant
+ check(xm7::V); //~ ERROR expected value, found struct variant `xm7::V`
check(xm8::V{}); //~ ERROR c::E
check(xm8::V); //~ ERROR c::Item
}
pub fn main() {
use namespaced_enums::Foo::*;
- foo(); //~ ERROR unresolved name `foo`
- m::foo(); //~ ERROR unresolved name `m::foo`
- bar(); //~ ERROR unresolved name `bar`
- m::bar(); //~ ERROR unresolved name `m::bar`
+ foo(); //~ ERROR unresolved function `foo`
+ m::foo(); //~ ERROR unresolved function `m::foo`
+ bar(); //~ ERROR unresolved function `bar`
+ m::bar(); //~ ERROR unresolved function `m::bar`
}
pub fn main() {
use m2::Foo::*;
- foo(); //~ ERROR unresolved name `foo`
- m::foo(); //~ ERROR unresolved name `m::foo`
- bar(); //~ ERROR unresolved name `bar`
- m::bar(); //~ ERROR unresolved name `m::bar`
+ foo(); //~ ERROR unresolved function `foo`
+ m::foo(); //~ ERROR unresolved function `m::foo`
+ bar(); //~ ERROR unresolved function `bar`
+ m::bar(); //~ ERROR unresolved function `m::bar`
}
#[cfg_attr(all(), cfg_attr(all(), cfg(foo)))]
fn f() {}
-fn main() { f() } //~ ERROR unresolved name `f`
+fn main() { f() } //~ ERROR unresolved function `f`
mod foo {
mod baz {
struct Test;
- impl Add for Test {} //~ ERROR: not in scope
- impl Clone for Test {} //~ ERROR: not in scope
- impl Iterator for Test {} //~ ERROR: not in scope
- impl ToString for Test {} //~ ERROR: not in scope
- impl Writer for Test {} //~ ERROR: not in scope
+ impl Add for Test {} //~ ERROR unresolved trait `Add`
+ impl Clone for Test {} //~ ERROR unresolved trait `Clone`
+ impl Iterator for Test {} //~ ERROR unresolved trait `Iterator`
+ impl ToString for Test {} //~ ERROR unresolved trait `ToString`
+ impl Writer for Test {} //~ ERROR unresolved trait `Writer`
fn foo() {
- drop(2) //~ ERROR: unresolved name
+ drop(2) //~ ERROR unresolved function `drop`
}
}
struct Test;
- impl Add for Test {} //~ ERROR: not in scope
- impl Clone for Test {} //~ ERROR: not in scope
- impl Iterator for Test {} //~ ERROR: not in scope
- impl ToString for Test {} //~ ERROR: not in scope
- impl Writer for Test {} //~ ERROR: not in scope
+ impl Add for Test {} //~ ERROR unresolved trait `Add`
+ impl Clone for Test {} //~ ERROR unresolved trait `Clone`
+ impl Iterator for Test {} //~ ERROR unresolved trait `Iterator`
+ impl ToString for Test {} //~ ERROR unresolved trait `ToString`
+ impl Writer for Test {} //~ ERROR unresolved trait `Writer`
fn foo() {
- drop(2) //~ ERROR: unresolved name
+ drop(2) //~ ERROR unresolved function `drop`
}
}
#[no_implicit_prelude]
mod qux_inner {
struct Test;
- impl Add for Test {} //~ ERROR: not in scope
- impl Clone for Test {} //~ ERROR: not in scope
- impl Iterator for Test {} //~ ERROR: not in scope
- impl ToString for Test {} //~ ERROR: not in scope
- impl Writer for Test {} //~ ERROR: not in scope
+ impl Add for Test {} //~ ERROR unresolved trait `Add`
+ impl Clone for Test {} //~ ERROR unresolved trait `Clone`
+ impl Iterator for Test {} //~ ERROR unresolved trait `Iterator`
+ impl ToString for Test {} //~ ERROR unresolved trait `ToString`
+ impl Writer for Test {} //~ ERROR unresolved trait `Writer`
fn foo() {
- drop(2) //~ ERROR: unresolved name
+ drop(2) //~ ERROR unresolved function `drop`
}
}
}
// fail with the same error message).
struct Test;
-impl Add for Test {} //~ ERROR: not in scope
-impl Clone for Test {} //~ ERROR: not in scope
-impl Iterator for Test {} //~ ERROR: not in scope
-impl ToString for Test {} //~ ERROR: not in scope
-impl Writer for Test {} //~ ERROR: not in scope
+impl Add for Test {} //~ ERROR unresolved trait `Add`
+impl Clone for Test {} //~ ERROR unresolved trait `Clone`
+impl Iterator for Test {} //~ ERROR unresolved trait `Iterator`
+impl ToString for Test {} //~ ERROR unresolved trait `ToString`
+impl Writer for Test {} //~ ERROR unresolved trait `Writer`
fn main() {
- drop(2) //~ ERROR: unresolved name
+ drop(2) //~ ERROR unresolved function `drop`
}
//~^ WARN custom derive crates and `#[no_link]` crates have no effect without `#[macro_use]`
fn main() {
- empty_struct::XEmpty1; //~ ERROR unresolved name
+ empty_struct::XEmpty1; //~ ERROR unresolved value `empty_struct::XEmpty1`
}
fn main() {
fn bar(n: isize) {
- // FIXME (#24414): This error message needs improvement.
let _x: [isize; n];
- //~^ ERROR no type for local variable
+ //~^ ERROR attempt to use a non-constant value in a constant [E0435]
+ //~| ERROR constant evaluation error [E0080]
}
}
fn main() {
fn bar(n: usize) {
let _x = [0; n];
- //~^ ERROR constant evaluation error
- //~| non-constant path in constant expression
- //~| NOTE `n` is a variable
+ //~^ 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]
}
}
trait Foo {
fn bar() {
- let x = foo(); //~ ERROR unresolved name `foo`
+ let x = foo(); //~ ERROR unresolved function `foo`
}
fn main() {
let x = y.; //~ ERROR unexpected token
- //~^ ERROR unresolved name `y`
+ //~^ ERROR unresolved value `y`
} //~ ERROR this file contains an un-closed delimiter
trait Foo {
fn bar() {
- let x = foo(); //~ ERROR unresolved name `foo`
+ let x = foo(); //~ ERROR unresolved function `foo`
) //~ ERROR incorrect close delimiter: `)`
}
fn main() {
let x = y.; //~ ERROR unexpected token
- //~^ ERROR unresolved name `y`
+ //~^ ERROR unresolved value `y`
}
fn main() {
let foo!() = 2;
- x + 1; //~ ERROR unresolved name `x`
+ x + 1; //~ ERROR unresolved value `x`
}
fn test_glob1() {
use foo1::*;
- Bar(); //~ ERROR unresolved name `Bar`
+ Bar(); //~ ERROR expected function, found trait `Bar`
}
// private type, public value
fn test_glob2() {
use foo2::*;
- let _x: Box<Bar>; //~ ERROR type name `Bar` is undefined or not in scope
+ let _x: Box<Bar>; //~ ERROR expected type, found function `Bar`
}
// neither public
fn test_glob3() {
use foo3::*;
- Bar(); //~ ERROR unresolved name `Bar`
- let _x: Box<Bar>; //~ ERROR type name `Bar` is undefined or not in scope
+ Bar(); //~ ERROR unresolved function `Bar`
+ let _x: Box<Bar>; //~ ERROR unresolved type `Bar`
}
fn main() {
fn test_single1() {
use foo1::Bar;
- Bar(); //~ ERROR unresolved name `Bar`
+ Bar(); //~ ERROR expected function, found trait `Bar`
}
fn test_list1() {
use foo1::{Bar,Baz};
- Bar(); //~ ERROR unresolved name `Bar`
+ Bar(); //~ ERROR expected function, found trait `Bar`
}
// private type, public value
fn test_single2() {
use foo2::Bar;
- let _x : Box<Bar>; //~ ERROR type name `Bar` is undefined
+ let _x : Box<Bar>; //~ ERROR expected type, found function `Bar`
}
fn test_list2() {
use foo2::{Bar,Baz};
- let _x: Box<Bar>; //~ ERROR type name `Bar` is undefined
+ let _x: Box<Bar>; //~ ERROR expected type, found function `Bar`
}
// neither public
}
mod pathological {
- pub(bad::path) mod m1 {} //~ ERROR failed to resolve module path
+ pub(bad::path) mod m1 {} //~ ERROR failed to resolve. Maybe a missing `extern crate bad;`?
pub(foo) mod m2 {} //~ ERROR visibilities can only be restricted to ancestor modules
}
struct S<T>(T);
m!{ S<u8> } //~ ERROR type or lifetime parameters in visibility path
-//~^ ERROR failed to resolve module path. Not a module `S`
+//~^ ERROR expected module, found struct `S`
mod foo {
struct S(pub(foo<T>) ()); //~ ERROR type or lifetime parameters in visibility path
- //~^ ERROR type name `T` is undefined or not in scope
+ //~^ ERROR unresolved type `T`
}
fn main() {}
// aux-build:recursive_reexports.rs
-fn f() -> recursive_reexports::S {} //~ ERROR undeclared
+extern crate recursive_reexports;
+
+fn f() -> recursive_reexports::S {} //~ ERROR unresolved type `recursive_reexports::S`
fn main() {}
fn main() {
let n = 1;
let a = [0; n];
- //~^ ERROR constant evaluation error
- //~| non-constant path in constant expression
+ //~^ ERROR attempt to use a non-constant value in a constant [E0435]
let b = [0; ()];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `()`
//~| expected usize, found ()
- //~| ERROR expected `usize` for repeat count, found tuple [E0306]
- //~| expected `usize`
let c = [0; true];
//~^ ERROR mismatched types
//~| expected usize, found bool
- //~| ERROR expected `usize` for repeat count, found boolean [E0306]
- //~| expected `usize`
let d = [0; 0.5];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `{float}`
//~| expected usize, found floating-point variable
- //~| ERROR expected `usize` for repeat count, found float [E0306]
- //~| expected `usize`
let e = [0; "foo"];
//~^ ERROR mismatched types
//~| expected type `usize`
//~| found type `&'static str`
//~| expected usize, found reference
- //~| ERROR expected `usize` for repeat count, found string literal [E0306]
- //~| expected `usize`
let f = [0; -4_isize];
- //~^ ERROR constant evaluation error
- //~| expected usize, found isize
- //~| ERROR mismatched types
+ //~^ ERROR mismatched types
//~| expected usize, found isize
let f = [0_usize; -1_isize];
- //~^ ERROR constant evaluation error
- //~| expected usize, found isize
- //~| ERROR mismatched types
+ //~^ ERROR mismatched types
//~| expected usize, found isize
struct G {
g: (),
//~| expected type `usize`
//~| found type `main::G`
//~| expected usize, found struct `main::G`
- //~| ERROR expected `usize` for repeat count, found struct [E0306]
- //~| expected `usize`
}
--- /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.
+
+mod m {}
+enum E {}
+struct S;
+trait Tr {}
+
+use {}; // OK
+use ::{}; // OK
+use m::{}; // OK
+use E::{}; // OK
+use S::{}; //~ ERROR expected module or enum, found struct `S`
+use Tr::{}; //~ ERROR expected module or enum, found trait `Tr`
+use Nonexistent::{}; //~ ERROR unresolved module or enum `Nonexistent`
+
+fn main () {}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(pub_restricted)]
+
+enum E {}
+trait Tr {}
+
+pub(E) struct S; //~ ERROR expected module, found enum `E`
+pub(Tr) struct Z; //~ ERROR expected module, found trait `Tr`
+pub(std::vec) struct F; //~ ERROR visibilities can only be restricted to ancestor modules
+pub(nonexistent) struct G; //~ ERROR unresolved module `nonexistent`
+pub(too_soon) struct H; //~ ERROR unresolved module `too_soon`
+
+// Visibilities are resolved eagerly without waiting for modules becoming fully populated.
+// Visibilities can only use ancestor modules legally which are always available in time,
+// so the worst thing that can happen due to eager resolution is a suboptimal error message.
+mod too_soon {}
+
+fn main () {}
+++ /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.
-
-fn main() {
- assert(true);
- //~^ ERROR unresolved name `assert`
- //~| NOTE did you mean the macro `assert!`?
-}
fn main() {
// Make sure primitive type fallback doesn't work in value namespace
std::mem::size_of(u16);
- //~^ ERROR unresolved name `u16`
+ //~^ ERROR expected value, found builtin type `u16`
//~| ERROR this function takes 0 parameters but 1 parameter was supplied
// Make sure primitive type fallback doesn't work with global paths
let _: ::u8;
- //~^ ERROR type name `u8` is undefined or not in scope
+ //~^ ERROR unresolved type `u8`
}
trait NewTrait : SomeNonExistentTrait {}
-//~^ ERROR trait `SomeNonExistentTrait` is not in scope
+//~^ ERROR unresolved trait `SomeNonExistentTrait`
impl SomeNonExistentTrait for isize {}
-//~^ ERROR trait `SomeNonExistentTrait` is not in scope
+//~^ ERROR unresolved trait `SomeNonExistentTrait`
fn f<T:SomeNonExistentTrait>() {}
-//~^ ERROR trait `SomeNonExistentTrait` is not in scope
+//~^ ERROR unresolved trait `SomeNonExistentTrait`
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-flags: --emit=metadata
// aux-build:rmeta_rlib.rs
// no-prefer-dynamic
// must-compile-successfully
// Check that building a metadata crate works with a dependent, rlib crate.
// This is a cfail test since there is no executable to run.
-#![crate_type="metadata"]
-
extern crate rmeta_rlib;
use rmeta_rlib::Foo;
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-flags: --emit=metadata
// aux-build:rmeta_meta.rs
// no-prefer-dynamic
// must-compile-successfully
// crate.
// This is a cfail test since there is no executable to run.
-#![crate_type="metadata"]
-
extern crate rmeta_meta;
use rmeta_meta::Foo;
--- /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: --emit=metadata
+// no-prefer-dynamic
+// must-compile-successfully
+
+#[deny(warnings)]
+
+// Test that we don't get warnings for non-pub main when only emitting metadata.
+// (#38273)
+
+fn main() {
+}
// except according to those terms.
// no-prefer-dynamic
+// compile-flags: --emit=metadata
// Check that building a metadata crate finds an error.
-#![crate_type="metadata"]
-
fn main() {
- let _ = Foo; //~ ERROR unresolved name `Foo`
+ let _ = Foo; //~ ERROR unresolved value `Foo`
}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// compile-flags: --emit=metadata
// aux-build:rmeta_meta.rs
// no-prefer-dynamic
// Check that building a metadata crate finds an error with a dependent,
// metadata-only crate.
-#![crate_type="metadata"]
extern crate rmeta_meta;
use rmeta_meta::Foo;
let x = 0;
let foo = Foo {
x,
- y //~ ERROR unresolved name `y`
+ y //~ ERROR unresolved value `y`
};
}
+++ /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.
-
-// Beginners write `mod.item` when they should write `mod::item`.
-// This tests that we suggest the latter when we encounter the former.
-
-pub mod a {
- pub const I: i32 = 1;
-
- pub fn f() -> i32 { 2 }
-
- pub mod b {
- pub const J: i32 = 3;
-
- pub fn g() -> i32 { 4 }
- }
-}
-
-fn h1() -> i32 {
- a.I
- //~^ ERROR E0425
- //~| HELP to reference an item from the `a` module, use `a::I`
-}
-
-fn h2() -> i32 {
- a.g()
- //~^ ERROR E0425
- //~| HELP to call a function from the `a` module, use `a::g(..)`
-}
-
-fn h3() -> i32 {
- a.b.J
- //~^ ERROR E0425
- //~| HELP to reference an item from the `a` module, use `a::b`
-}
-
-fn h4() -> i32 {
- a::b.J
- //~^ ERROR E0425
- //~| HELP to reference an item from the `a::b` module, use `a::b::J`
-}
-
-fn h5() {
- a.b.f();
- //~^ ERROR E0425
- //~| HELP to reference an item from the `a` module, use `a::b`
- let v = Vec::new();
- v.push(a::b);
- //~^ ERROR E0425
- //~| HELP module `a::b` cannot be used as an expression
-}
-
-fn h6() -> i32 {
- a::b.f()
- //~^ ERROR E0425
- //~| HELP to call a function from the `a::b` module, use `a::b::f(..)`
-}
-
-fn h7() {
- a::b
- //~^ ERROR E0425
- //~| HELP module `a::b` cannot be used as an expression
-}
-
-fn h8() -> i32 {
- a::b()
- //~^ ERROR E0425
- //~| HELP module `a::b` cannot be used as an expression
-}
// this now fails (correctly, I claim) because hygiene prevents
// the assembled identifier from being a reference to the binding.
assert!(concat_idents!(asd, f_f, dsa) == "<.<".to_string());
- //~^ ERROR: unresolved name `asdf_fdsa`
+ //~^ ERROR unresolved value `asdf_fdsa`
assert_eq!(stringify!(use_mention_distinction), "use_mention_distinction");
}
fn foo() {}
fn main() {
- foo(); //~ ERROR unresolved name `foo`
+ foo(); //~ ERROR unresolved function `foo`
}
+++ /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.
-
-// Test that we do some basic error correcton in the tokeniser (and don't ICE).
-
-fn main() {
- if foo { //~ NOTE: unclosed delimiter
- //~^ ERROR: unresolved name `foo`
- //~| NOTE unresolved name
- ) //~ ERROR: incorrect close delimiter: `)`
-}
+++ /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.
-
-// Test that we do some basic error correcton in the tokeniser (and don't spew
-// too many bogus errors).
-
-pub mod raw {
- use std::{io, fs};
- use std::path::Path;
-
- pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
- callback: F)
- -> io::Result<bool> {
- if !is_directory(path.as_ref()) { //~ ERROR: unresolved name `is_directory`
- //~| NOTE unresolved name
- callback(path.as_ref(); //~ NOTE: unclosed delimiter
- //~^ ERROR: expected one of
- fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
- //~^ expected (), found enum `std::result::Result`
- //~| expected type `()`
- //~| found type `std::result::Result<bool, std::io::Error>`
- } else { //~ ERROR: incorrect close delimiter: `}`
- //~^ ERROR: expected one of
- Ok(false);
- }
-
- panic!();
- }
-}
-
-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.
-
-// Test that we do some basic error correcton in the tokeniser.
-
-fn main() {
- foo(bar(; //~ NOTE: unclosed delimiter
- //~^ NOTE: unclosed delimiter
- //~^^ ERROR: expected expression, found `;`
- //~^^^ ERROR: unresolved name `bar`
- //~^^^^ ERROR: unresolved name `foo`
- //~^^^^^ ERROR: expected one of `)`, `,`, `.`, `<`, `?`
- //~| NOTE unresolved name
- //~| NOTE unresolved name
-} //~ ERROR: incorrect close delimiter: `}`
-//~^ ERROR: incorrect close delimiter: `}`
-//~^^ ERROR: expected expression, found `)`
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![feature(associated_type_defaults)]
+
+trait Tr {
+ type Y = u16;
+ fn Y() {}
+}
+impl Tr for u8 {}
+
+trait Dr {
+ type X = u16;
+ fn Z() {}
+}
+impl Dr for u8 {}
+
+enum E { Y }
+type A = u32;
+
+fn main() {
+ let _: <u8 as Tr>::N; //~ ERROR unresolved associated type `Tr::N`
+ let _: <u8 as E>::N; //~ ERROR unresolved associated type `E::N`
+ let _: <u8 as A>::N; //~ ERROR unresolved associated type `A::N`
+ <u8 as Tr>::N; //~ ERROR unresolved method or associated constant `Tr::N`
+ <u8 as E>::N; //~ ERROR unresolved method or associated constant `E::N`
+ <u8 as A>::N; //~ ERROR unresolved method or associated constant `A::N`
+ let _: <u8 as Tr>::Y; // OK
+ let _: <u8 as E>::Y; //~ ERROR expected associated type, found variant `E::Y`
+ <u8 as Tr>::Y; // OK
+ <u8 as E>::Y; //~ ERROR expected method or associated constant, found unit variant `E::Y`
+
+ let _: <u8 as Tr>::N::NN; //~ ERROR unresolved associated type `Tr::N`
+ let _: <u8 as E>::N::NN; //~ ERROR unresolved associated type `E::N`
+ let _: <u8 as A>::N::NN; //~ ERROR unresolved associated type `A::N`
+ <u8 as Tr>::N::NN; //~ ERROR unresolved associated type `Tr::N`
+ <u8 as E>::N::NN; //~ ERROR unresolved associated type `E::N`
+ <u8 as A>::N::NN; //~ ERROR unresolved associated type `A::N`
+ let _: <u8 as Tr>::Y::NN; //~ ERROR ambiguous associated type
+ let _: <u8 as E>::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
+ <u8 as Tr>::Y::NN; //~ ERROR no associated item named `NN` found for type `<u8 as Tr>::Y`
+ <u8 as E>::Y::NN; //~ ERROR expected associated type, found variant `E::Y`
+
+ let _: <u8 as Tr::N>::NN; //~ ERROR unresolved associated type `Tr::N::NN`
+ let _: <u8 as E::N>::NN; //~ ERROR unresolved associated type `E::N::NN`
+ let _: <u8 as A::N>::NN; //~ ERROR unresolved associated type `A::N::NN`
+ <u8 as Tr::N>::NN; //~ ERROR unresolved method or associated constant `Tr::N::NN`
+ <u8 as E::N>::NN; //~ ERROR unresolved method or associated constant `E::N::NN`
+ <u8 as A::N>::NN; //~ ERROR unresolved method or associated constant `A::N::NN`
+ let _: <u8 as Tr::Y>::NN; //~ ERROR unresolved associated type `Tr::Y::NN`
+ let _: <u8 as E::Y>::NN; //~ ERROR unresolved associated type `E::Y::NN`
+ <u8 as Tr::Y>::NN; //~ ERROR unresolved method or associated constant `Tr::Y::NN`
+ <u8 as E::Y>::NN; //~ ERROR unresolved method or associated constant `E::Y::NN`
+
+ let _: <u8 as Dr>::Z; //~ ERROR expected associated type, found method `Dr::Z`
+ <u8 as Dr>::X; //~ ERROR expected method or associated constant, found associated type `Dr::X`
+ let _: <u8 as Dr>::Z::N; //~ ERROR expected associated type, found method `Dr::Z`
+ <u8 as Dr>::X::N; //~ ERROR no associated item named `N` found for type `<u8 as Dr>::X`
+}
+++ /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.
-
-fn f<F:Nonexist(isize) -> isize>(x: F) {} //~ ERROR trait `Nonexist` is not in scope
-
-type Typedef = isize;
-
-fn g<F:Typedef(isize) -> isize>(x: F) {} //~ ERROR `Typedef` is not a trait
-
-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.
-
-fn f(_: bool) {}
-
-struct Foo {
- cx: bool,
-}
-
-impl Foo {
- fn bar() {
- f(cx); //~ ERROR E0425
- //~| HELP this is an associated function
- }
-}
-
-fn main() {}
enum Ty {
A,
B(Ty::A),
- //~^ ERROR: found value `Ty::A` used as a type
+ //~^ ERROR expected type, found variant `Ty::A`
}
}
impl E::A {}
-//~^ ERROR: found value `E::A` used as a type
+//~^ ERROR expected type, found variant `E::A`
fn main() {}
fn main() {
let _ = xcrate_unit_struct::StructWithFields;
- //~^ ERROR: `xcrate_unit_struct::StructWithFields` is the name of a struct or struct variant
+ //~^ ERROR expected value, found struct `xcrate_unit_struct::StructWithFields`
let _ = xcrate_unit_struct::Struct;
}
// except according to those terms.
// min-lldb-version: 310
+// ignore-macos FIXME(#37479)
// compile-flags:-g
const CONST_CHANGE_VALUE_1: i16 = 1;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[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="cfail3")]
const CONST_CHANGE_VALUE_1: i16 = 2;
const CONST_CHANGE_VALUE_2: i16 = 1 + 1;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[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="cfail3")]
const CONST_CHANGE_VALUE_2: i16 = 1 + 2;
const CONST_CHANGE_VALUE_3: i16 = 2 + 3;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[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="cfail3")]
const CONST_CHANGE_VALUE_3: i16 = 2 * 3;
const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[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="cfail3")]
const CONST_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[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="cfail3")]
enum EnumChangeValueCStyleVariant0 {
#[cfg(not(cfail1))]
#[rustc_dirty(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_clean(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
enum EnumChangeValueCStyleVariant1 {
--- /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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for `extern` modules.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![feature(unboxed_closures)]
+#![feature(link_args)]
+#![crate_type="rlib"]
+
+
+// Change function name --------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn change_function_name1(c: i64) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn change_function_name2(c: i64) -> i32;
+}
+
+
+
+// Change parameter name -------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn change_parameter_name(c: i64) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn change_parameter_name(d: i64) -> i32;
+}
+
+
+
+// Change parameter type -------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn change_parameter_type(c: i64) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn change_parameter_type(c: i32) -> i32;
+}
+
+
+
+// Change return type ----------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn change_return_type(c: i32) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn change_return_type(c: i32) -> i8;
+}
+
+
+
+// Add parameter ---------------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn add_parameter(c: i32) -> i32;
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn add_parameter(c: i32, d: i32) -> i32;
+}
+
+
+
+// Add return type -------------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn add_return_type(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn add_return_type(c: i32) -> i32;
+}
+
+
+
+// Make function variadic ------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn make_function_variadic(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn make_function_variadic(c: i32, ...);
+}
+
+
+
+// Change calling convention ---------------------------------------------------
+#[cfg(cfail1)]
+extern "C" {
+ pub fn change_calling_convention(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern "rust-call" {
+ pub fn change_calling_convention(c: i32);
+}
+
+
+
+// Make function public --------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ fn make_function_public(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn make_function_public(c: i32);
+}
+
+
+
+// Add function ----------------------------------------------------------------
+#[cfg(cfail1)]
+extern {
+ pub fn add_function1(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+extern {
+ pub fn add_function1(c: i32);
+ pub fn add_function2();
+}
+
+
+
+// Change link-args ------------------------------------------------------------
+#[cfg(cfail1)]
+#[link_args = "-foo -bar"]
+extern {
+ pub fn change_link_args(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[link_args = "-foo -bar -baz"]
+extern {
+ pub fn change_link_args(c: i32);
+}
+
+
+
+// Change link-name ------------------------------------------------------------
+#[cfg(cfail1)]
+#[link(name = "foo")]
+extern {
+ pub fn change_link_name(c: i32);
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[link(name = "bar")]
+extern {
+ pub fn change_link_name(c: i32);
+}
+
+type c_i32 = i32;
+type c_i64 = i64;
+
+// Indirectly change parameter type --------------------------------------------
+mod indirectly_change_parameter_type {
+ #[cfg(cfail1)]
+ use super::c_i32 as c_int;
+ #[cfg(not(cfail1))]
+ use super::c_i64 as c_int;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ extern {
+ pub fn indirectly_change_parameter_type(c: c_int);
+ }
+}
+
+
+
+// Indirectly change return type --------------------------------------------
+mod indirectly_change_return_type {
+ #[cfg(cfail1)]
+ use super::c_i32 as c_int;
+ #[cfg(not(cfail1))]
+ use super::c_i64 as c_int;
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ extern {
+ pub fn indirectly_change_return_type() -> c_int;
+ }
+}
pub fn method_selfness(&self) { }
}
-// Change Method Selfmutness -----------------------------------------------------------
+// Change Method Selfmutness ---------------------------------------------------
#[cfg(cfail1)]
impl Foo {
pub fn method_selfmutness(&self) { }
pub fn method_selfmutness(&mut self) { }
}
+
+
+// Add Method To Impl ----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn add_method_to_impl1(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_clean(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_clean(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_method_to_impl1(&self) { }
+
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_method_to_impl2(&self) { }
+}
+
+
+
+// Add Method Parameter --------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn add_method_parameter(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_method_parameter(&self, _: i32) { }
+}
+
+
+
+// Change Method Parameter Name ------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn change_method_parameter_name(&self, a: i64) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn change_method_parameter_name(&self, b: i64) { }
+}
+
+
+
+// Change Method Return Type ---------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn change_method_return_type(&self) -> u16 { 0 }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn change_method_return_type(&self) -> u8 { 0 }
+}
+
+
+
+// Make Method #[inline] -------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn make_method_inline(&self) -> u8 { 0 }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ #[inline]
+ pub fn make_method_inline(&self) -> u8 { 0 }
+}
+
+
+
+// Change order of parameters -------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn change_method_parameter_order(&self, a: i64, b: i64) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn change_method_parameter_order(&self, b: i64, a: i64) { }
+}
+
+
+
+// Make method unsafe ----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn make_method_unsafe(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub unsafe fn make_method_unsafe(&self) { }
+}
+
+
+
+// Make method extern ----------------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn make_method_extern(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub extern fn make_method_extern(&self) { }
+}
+
+
+
+// Change method calling convention --------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub extern "C" fn change_method_calling_convention(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub extern "system" fn change_method_calling_convention(&self) { }
+}
+
+
+
+// Add Lifetime Parameter to Method --------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn add_lifetime_parameter_to_method(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_lifetime_parameter_to_method<'a>(&self) { }
+}
+
+
+
+// Add Type Parameter To Method ------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn add_type_parameter_to_method(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_type_parameter_to_method<T>(&self) { }
+}
+
+
+
+// Add Lifetime Bound to Lifetime Parameter of Method --------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b>(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_lifetime_bound_to_lifetime_param_of_method<'a, 'b: 'a>(&self) { }
+}
+
+
+
+// Add Lifetime Bound to Type Parameter of Method ------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn add_lifetime_bound_to_type_param_of_method<'a, T>(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_lifetime_bound_to_type_param_of_method<'a, T: 'a>(&self) { }
+}
+
+
+
+// Add Trait Bound to Type Parameter of Method ------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn add_trait_bound_to_type_param_of_method<T>(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_trait_bound_to_type_param_of_method<T: Clone>(&self) { }
+}
+
+
+
+// Add #[no_mangle] to Method --------------------------------------------------
+#[cfg(cfail1)]
+impl Foo {
+ pub fn add_no_mangle_to_method(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Foo {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ #[no_mangle]
+ pub fn add_no_mangle_to_method(&self) { }
+}
+
+
+
+struct Bar<T>(T);
+
+// Add Type Parameter To Impl --------------------------------------------------
+#[cfg(cfail1)]
+impl Bar<u32> {
+ pub fn add_type_parameter_to_impl(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl<T> Bar<T> {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_type_parameter_to_impl(&self) { }
+}
+
+
+
+// Change Self Type of Impl ----------------------------------------------------
+#[cfg(cfail1)]
+impl Bar<u32> {
+ pub fn change_impl_self_type(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl Bar<u64> {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn change_impl_self_type(&self) { }
+}
+
+
+
+// Add Lifetime Bound to Impl --------------------------------------------------
+#[cfg(cfail1)]
+impl<T> Bar<T> {
+ pub fn add_lifetime_bound_to_impl_parameter(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl<T: 'static> Bar<T> {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_lifetime_bound_to_impl_parameter(&self) { }
+}
+
+
+
+// Add Trait Bound to Impl Parameter -------------------------------------------
+#[cfg(cfail1)]
+impl<T> Bar<T> {
+ pub fn add_trait_bound_to_impl_parameter(&self) { }
+}
+
+#[cfg(not(cfail1))]
+#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+impl<T: Clone> Bar<T> {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
+ pub fn add_trait_bound_to_impl_parameter(&self) { }
+}
--- /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.
+
+
+// This test case tests the incremental compilation hash (ICH) implementation
+// for inline asm.
+
+// The general pattern followed here is: Change one thing between rev1 and rev2
+// and make sure that the hash has changed, then change nothing between rev2 and
+// rev3 and make sure that the hash has not changed.
+
+// must-compile-successfully
+// revisions: cfail1 cfail2 cfail3
+// compile-flags: -Z query-dep-graph
+
+#![allow(warnings)]
+#![feature(rustc_attrs)]
+#![feature(asm)]
+#![crate_type="rlib"]
+
+
+
+// Change template -------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_template(a: i32) -> i32 {
+ let c: i32;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(c)
+ : "0"(a)
+ :
+ :
+ );
+ }
+ c
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_template(a: i32) -> i32 {
+ let c: i32;
+ unsafe {
+ asm!("add 2, $0"
+ : "=r"(c)
+ : "0"(a)
+ :
+ :
+ );
+ }
+ c
+}
+
+
+
+// Change output -------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_output(a: i32) -> i32 {
+ let mut _out1: i32 = 0;
+ let mut _out2: i32 = 0;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out1)
+ : "0"(a)
+ :
+ :
+ );
+ }
+ _out1
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_output(a: i32) -> i32 {
+ let mut _out1: i32 = 0;
+ let mut _out2: i32 = 0;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out2)
+ : "0"(a)
+ :
+ :
+ );
+ }
+ _out1
+}
+
+
+
+// Change input -------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_input(_a: i32, _b: i32) -> i32 {
+ let _out;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out)
+ : "0"(_a)
+ :
+ :
+ );
+ }
+ _out
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_input(_a: i32, _b: i32) -> i32 {
+ let _out;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out)
+ : "0"(_b)
+ :
+ :
+ );
+ }
+ _out
+}
+
+
+
+// Change input constraint -----------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_input_constraint(_a: i32, _b: i32) -> i32 {
+ let _out;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out)
+ : "0"(_a), "r"(_b)
+ :
+ :
+ );
+ }
+ _out
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_input_constraint(_a: i32, _b: i32) -> i32 {
+ let _out;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out)
+ : "r"(_a), "0"(_b)
+ :
+ :
+ );
+ }
+ _out
+}
+
+
+
+// Change clobber --------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_clobber(_a: i32) -> i32 {
+ let _out;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out)
+ : "0"(_a)
+ :
+ :
+ );
+ }
+ _out
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_clobber(_a: i32) -> i32 {
+ let _out;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out)
+ : "0"(_a)
+ : "eax"
+ :
+ );
+ }
+ _out
+}
+
+
+
+// Change options --------------------------------------------------------------
+#[cfg(cfail1)]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_options(_a: i32) -> i32 {
+ let _out;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out)
+ : "0"(_a)
+ :
+ :
+ );
+ }
+ _out
+}
+
+#[cfg(not(cfail1))]
+#[rustc_clean(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail3")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail3")]
+#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+fn change_options(_a: i32) -> i32 {
+ let _out;
+ unsafe {
+ asm!("add 1, $0"
+ : "=r"(_out)
+ : "0"(_a)
+ :
+ : "volatile"
+ );
+ }
+ _out
+}
+
+
+
static STATIC_CHANGE_VALUE_1: i16 = 1;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
static STATIC_CHANGE_VALUE_1: i16 = 2;
static STATIC_CHANGE_VALUE_2: i16 = 1 + 1;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
static STATIC_CHANGE_VALUE_2: i16 = 1 + 2;
static STATIC_CHANGE_VALUE_3: i16 = 2 + 3;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
static STATIC_CHANGE_VALUE_3: i16 = 2 * 3;
static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 3;
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_dirty(label="HirBody", cfg="cfail2")]
+#[rustc_clean(label="HirBody", cfg="cfail3")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
static STATIC_CHANGE_VALUE_4: i16 = 1 + 2 * 4;
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddReturnType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method() -> u32;
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeReturnType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method() -> u64;
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddParameterToMethod {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(a: u32);
}
#[cfg(cfail1)]
trait TraitChangeMethodParameterName {
fn method(a: u32);
+ fn with_default(x: i32) {}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeMethodParameterName {
+ // FIXME(#38501) This should preferably always be clean.
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(b: u32);
+
+ #[rustc_clean(label="Hir", cfg="cfail2")]
+ #[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="cfail3")]
+ fn with_default(y: i32) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeMethodParameterType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(a: i64);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeMethodParameterTypeRef {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(a: &mut i32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeMethodParametersOrder {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(b: i64, a: i32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeModeSelfRefToMut {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(&mut self);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
-#[rustc_metadata_dirty(cfg="cfail2")]
+#[rustc_metadata_clean(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeModeSelfOwnToMut: Sized {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(mut self) {}
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeModeSelfOwnToRef {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(&self);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddUnsafeModifier {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
unsafe fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddExternModifier {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
extern fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeExternCToRustIntrinsic {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
extern "rust-intrinsic" fn method();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddTypeParameterToMethod {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddLifetimeParameterToMethod {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<'a>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddTraitBoundToMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: ReferencedTrait0>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddBuiltinBoundToMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: Sized>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToMethodLifetimeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddSecondTraitBoundToMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: ReferencedTrait0 + ReferencedTrait1>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddSecondBuiltinBoundToMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: Sized + Sync>();
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32);
}
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddTraitBoundToAssociatedType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
type Associated: ReferencedTrait0;
fn mathod();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitAddLifetimeBoundToAssociatedType<'a> {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
type Associated: 'a;
fn mathod();
}
#[cfg(not(cfail1))]
-#[rustc_dirty(label="Hir", cfg="cfail2")]
+#[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeTypeOfAssociatedConstant {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
const Value: f64;
fn mathod();
#[cfg(not(cfail1))]
use super::ReferenceType1 as ReturnType;
- #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeReturnType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method() -> ReturnType;
}
}
#[cfg(not(cfail1))]
use super::ReferenceType1 as ArgType;
- #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeArgType {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method(a: ArgType);
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeBoundOfMethodTypeParameter {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T: Bound>(a: T);
}
}
#[cfg(not(cfail1))]
use super::ReferencedTrait1 as Bound;
- #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail2")]
#[rustc_clean(label="Hir", cfg="cfail3")]
#[rustc_metadata_dirty(cfg="cfail2")]
#[rustc_metadata_clean(cfg="cfail3")]
trait TraitChangeBoundOfMethodTypeParameterWhere {
+ #[rustc_dirty(label="Hir", cfg="cfail2")]
+ #[rustc_clean(label="Hir", cfg="cfail3")]
+ #[rustc_metadata_dirty(cfg="cfail2")]
+ #[rustc_metadata_clean(cfg="cfail3")]
fn method<T>(a: T) where T: Bound;
}
}
mod x {
#[cfg(rpass1)]
pub fn x() {
- println!("1");
+ println!("{}", "1");
}
#[cfg(rpass2)]
#[rustc_dirty(label="TypeckItemBody", cfg="rpass2")]
#[rustc_dirty(label="TransCrateItem", cfg="rpass2")]
pub fn x() {
- println!("2");
+ println!("{}", "2");
}
}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z parse-only
+
+fn foo<T>() where <T>::Item: ToString, T: Iterator { }
+ //~^ syntax `where<T>` is reserved for future use
+
+fn main() {}
- (($crate::fmt::format as
+ ((::fmt::format as
fn(std::fmt::Arguments<'_>) -> std::string::String {std::fmt::format})(((<::std::fmt::Arguments>::new_v1
as
fn(&[&str], &[std::fmt::ArgumentV1<'_>]) -> std::fmt::Arguments<'_> {std::fmt::Arguments<'_>::new_v1})(({
digraph block {
N0[label="entry"];
N1[label="exit"];
- N2[label="stmt "];
+ N2[label="stmt fn inner(x: isize) -> isize { x + x }"];
N3[label="expr inner"];
N4[label="expr inner"];
N5[label="expr 18"];
N6[label="expr inner(18)"];
N7[label="expr inner(inner(18))"];
N8[label="stmt inner(inner(18));"];
- N9[label="block { inner(inner(18)); }"];
- N10[label="expr { inner(inner(18)); }"];
+ N9[label="block {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"];
+ N10[label="expr {\l fn inner(x: isize) -> isize { x + x }\l inner(inner(18));\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
digraph block {
N0[label="entry"];
N1[label="exit"];
- N2[label="stmt "];
- N3[label="stmt "];
+ N2[label="stmt struct S19 {\l x: isize,\l}\l"];
+ N3[label="stmt impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l}\l"];
N4[label="expr 19"];
N5[label="expr S19{x: 19,}"];
N6[label="local s"];
N9[label="expr s.inner()"];
N10[label="expr s.inner().inner()"];
N11[label="stmt s.inner().inner();"];
- N12[label="block { let s = S19{x: 19,}; s.inner().inner(); }"];
- N13[label="expr { let s = S19{x: 19,}; s.inner().inner(); }"];
+ N12[label="block {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"];
+ N13[label="expr {\l struct S19 {\l x: isize,\l }\l impl S19 {\l fn inner(self: Self) -> S19 { S19{x: self.x + self.x,} }\l }\l let s = S19{x: 19,};\l s.inner().inner();\l}\l"];
N0 -> N2;
N2 -> N3;
N3 -> N4;
--- /dev/null
+-include ../tools.mk
+
+all:
+ $(RUSTC) foo.rs; $(RUSTC) bar.rs
+ $(RUSTDOC) baz.rs -L $(TMPDIR) -o $(TMPDIR)
--- /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.
+
+#![crate_type = "lib"]
+
+#[derive(Debug)]
+pub struct S;
--- /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.
+
+extern crate foo;
+extern crate bar;
+
+pub struct Bar;
+impl ::std::ops::Deref for Bar {
+ type Target = bar::S;
+ fn deref(&self) -> &Self::Target { unimplemented!() }
+}
--- /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.
+
+#![crate_type = "proc-macro"]
+#![feature(proc_macro, proc_macro_lib)]
+
+extern crate proc_macro;
+
+#[proc_macro_derive(A)]
+pub fn derive(ts: proc_macro::TokenStream) -> proc_macro::TokenStream { ts }
+
+#[derive(Debug)]
+struct S;
-fn foo_method(&self) -> &'static str { return "i am very similar to foo."; }
-/* nest::{{impl}}::foo_method */
+fn foo_method(self: &Self)
+ -> &'static str { return "i am very similar to foo."; } /*
+nest::{{impl}}::foo_method */
#[plugin_registrar]
pub fn plugin_registrar(reg: &mut Registry) {
- reg.register_syntax_extension(
+ reg.register_custom_derive(
Symbol::intern("derive_TotalSum"),
MultiDecorator(box expand));
}
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for Pass {
fn check_fn(&mut self, cx: &LateContext,
- fk: FnKind, _: &hir::FnDecl, expr: &hir::Expr,
+ fk: FnKind, _: &hir::FnDecl, body: &hir::Body,
span: Span, node: ast::NodeId)
{
if let FnKind::Closure(..) = fk { return }
- let mut extent = cx.tcx.region_maps.node_extent(expr.id);
+ let mut extent = cx.tcx.region_maps.node_extent(body.value.id);
while let Some(parent) = cx.tcx.region_maps.opt_encl_scope(extent) {
extent = parent;
}
// except according to those terms.
// no-prefer-dynamic
+// compile-flags: --emit=metadata
-#![crate_type="metadata"]
+#![crate_type="rlib"]
#![crate_name="rmeta_aux"]
pub struct Foo {
--- /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.
+
+// Check that drop elaboration clears the "master" discriminant
+// drop flag even if it protects no fields.
+
+struct Good(usize);
+impl Drop for Good {
+ #[inline(never)]
+ fn drop(&mut self) {
+ println!("dropping Good({})", self.0);
+ }
+}
+
+struct Void;
+impl Drop for Void {
+ #[inline(never)]
+ fn drop(&mut self) {
+ panic!("Suddenly, a Void appears.");
+ }
+}
+
+enum E {
+ Never(Void),
+ Fine(Good)
+}
+
+fn main() {
+ let mut go = true;
+
+ loop {
+ let next;
+ match go {
+ true => next = E::Fine(Good(123)),
+ false => return,
+ }
+
+ match next {
+ E::Never(_) => return,
+ E::Fine(_good) => go = false,
+ }
+
+ // `next` is dropped and StorageDead'd here. We must reset the
+ // discriminant's drop flag to avoid random variants being
+ // dropped.
+ }
+}
--- /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.
+
+pub struct Foo;
+
+macro_rules! reexport {
+ () => { use Foo as Bar; }
+}
+
+reexport!();
+
+fn main() {
+ use Bar;
+ fn f(_: Bar) {}
+}
a([u16; 0], u8), b
}
-// Test struct field reordering to make sure it actually reorders.
-struct WillOptimize1(u8, u16, u8);
-struct WillOptimize2 { a: u8, b: u16, c: u8}
-
pub fn main() {
assert_eq!(size_of::<u8>(), 1 as usize);
assert_eq!(size_of::<u32>(), 4 as usize);
assert_eq!(size_of::<e1>(), 8 as usize);
assert_eq!(size_of::<e2>(), 8 as usize);
assert_eq!(size_of::<e3>(), 4 as usize);
-
- assert_eq!(size_of::<WillOptimize1>(), 4);
- assert_eq!(size_of::<WillOptimize2>(), 4);
}
--- /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.
+
+#![crate_name = "foo"]
+
+// @has 'search-index.js' 'Foo short link.'
+// @!has - 'www.example.com'
+// @!has - 'More Foo.'
+
+/// Foo short [link](https://www.example.com/).
+///
+/// More Foo.
+pub struct Foo;
-error[E0425]: unresolved name `bar`
+error[E0425]: unresolved value `bar`
--> $DIR/tab.rs:14:2
|
14 | \tbar;
- | \t^^^ unresolved name
+ | \t^^^ no resolution found
error: aborting due to previous error
-error[E0404]: `Bar` is not a trait
+error[E0404]: expected trait, found type alias `Bar`
--> $DIR/two_files.rs:15:6
|
15 | impl Bar for Baz { }
- | ^^^ expected trait, found type alias
- |
- = note: type aliases cannot be used for traits
+ | ^^^ type aliases cannot be used for traits
error: cannot continue compilation due to previous error
-error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́`
+error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, ptx-kernel, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́`
--> $DIR/unicode.rs:11:8
|
11 | extern "路濫狼á́́" fn foo() {}
-error[E0425]: unresolved name `fake`
+error[E0425]: unresolved value `fake`
--> $DIR/macro-backtrace-nested.rs:15:12
|
15 | () => (fake)
- | ^^^^ unresolved name
+ | ^^^^ no resolution found
...
27 | 1 + call_nested_expr!();
| ------------------- in this macro invocation
-error[E0425]: unresolved name `fake`
+error[E0425]: unresolved value `fake`
--> $DIR/macro-backtrace-nested.rs:15:12
|
15 | () => (fake)
- | ^^^^ unresolved name
+ | ^^^^ no resolution found
...
28 | call_nested_expr_sum!();
| ------------------------ in this macro invocation
-print-type-size type: `IndirectNonZero<u32>`: 12 bytes, alignment: 4 bytes
-print-type-size field `.nested`: 8 bytes
-print-type-size field `.post`: 2 bytes
+print-type-size type: `IndirectNonZero<u32>`: 20 bytes, alignment: 4 bytes
print-type-size field `.pre`: 1 bytes
-print-type-size end padding: 1 bytes
-print-type-size type: `MyOption<IndirectNonZero<u32>>`: 12 bytes, alignment: 4 bytes
-print-type-size variant `Some`: 12 bytes
-print-type-size field `.0`: 12 bytes
-print-type-size type: `EmbeddedDiscr`: 8 bytes, alignment: 4 bytes
-print-type-size variant `Record`: 7 bytes
-print-type-size field `.val`: 4 bytes
-print-type-size field `.post`: 2 bytes
-print-type-size field `.pre`: 1 bytes
-print-type-size end padding: 1 bytes
-print-type-size type: `NestedNonZero<u32>`: 8 bytes, alignment: 4 bytes
-print-type-size field `.val`: 4 bytes
+print-type-size padding: 3 bytes
+print-type-size field `.nested`: 12 bytes, alignment: 4 bytes
print-type-size field `.post`: 2 bytes
+print-type-size end padding: 2 bytes
+print-type-size type: `MyOption<IndirectNonZero<u32>>`: 20 bytes, alignment: 4 bytes
+print-type-size variant `Some`: 20 bytes
+print-type-size field `.0`: 20 bytes
+print-type-size type: `EmbeddedDiscr`: 12 bytes, alignment: 4 bytes
+print-type-size variant `Record`: 10 bytes
+print-type-size field `.pre`: 1 bytes
+print-type-size padding: 3 bytes
+print-type-size field `.val`: 4 bytes, alignment: 4 bytes
+print-type-size field `.post`: 2 bytes
+print-type-size end padding: 2 bytes
+print-type-size type: `NestedNonZero<u32>`: 12 bytes, alignment: 4 bytes
print-type-size field `.pre`: 1 bytes
-print-type-size end padding: 1 bytes
+print-type-size padding: 3 bytes
+print-type-size field `.val`: 4 bytes, alignment: 4 bytes
+print-type-size field `.post`: 2 bytes
+print-type-size end padding: 2 bytes
print-type-size type: `MyOption<core::nonzero::NonZero<u32>>`: 4 bytes, alignment: 4 bytes
print-type-size variant `Some`: 4 bytes
print-type-size field `.0`: 4 bytes
-print-type-size type: `Padded`: 12 bytes, alignment: 4 bytes
-print-type-size field `.g`: 4 bytes
-print-type-size field `.h`: 2 bytes
+print-type-size type: `Padded`: 16 bytes, alignment: 4 bytes
print-type-size field `.a`: 1 bytes
print-type-size field `.b`: 1 bytes
+print-type-size padding: 2 bytes
+print-type-size field `.g`: 4 bytes, alignment: 4 bytes
print-type-size field `.c`: 1 bytes
+print-type-size padding: 1 bytes
+print-type-size field `.h`: 2 bytes, alignment: 2 bytes
print-type-size field `.d`: 1 bytes
-print-type-size end padding: 2 bytes
+print-type-size end padding: 3 bytes
print-type-size type: `Packed`: 10 bytes, alignment: 1 bytes
print-type-size field `.a`: 1 bytes
print-type-size field `.b`: 1 bytes
print-type-size type: `E1`: 12 bytes, alignment: 4 bytes
-print-type-size discriminant: 1 bytes
-print-type-size variant `A`: 7 bytes
+print-type-size discriminant: 4 bytes
+print-type-size variant `A`: 5 bytes
+print-type-size field `.0`: 4 bytes
print-type-size field `.1`: 1 bytes
-print-type-size padding: 2 bytes
-print-type-size field `.0`: 4 bytes, alignment: 4 bytes
-print-type-size variant `B`: 11 bytes
-print-type-size padding: 3 bytes
-print-type-size field `.0`: 8 bytes, alignment: 4 bytes
+print-type-size variant `B`: 8 bytes
+print-type-size field `.0`: 8 bytes
print-type-size type: `E2`: 12 bytes, alignment: 4 bytes
print-type-size discriminant: 1 bytes
print-type-size variant `A`: 7 bytes
print-type-size padding: 3 bytes
print-type-size field `.0`: 8 bytes, alignment: 4 bytes
print-type-size type: `S`: 8 bytes, alignment: 4 bytes
-print-type-size field `.g`: 4 bytes
print-type-size field `.a`: 1 bytes
print-type-size field `.b`: 1 bytes
-print-type-size end padding: 2 bytes
+print-type-size padding: 2 bytes
+print-type-size field `.g`: 4 bytes, alignment: 4 bytes
--- /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.
+
+// testing whether the lookup mechanism picks up types
+// defined in the outside crate
+
+#![crate_type="lib"]
+
+pub mod outer {
+ // should suggest this
+ pub trait OuterTrait {}
+
+ // should not suggest this since the module is private
+ mod private_module {
+ pub trait OuterTrait {}
+ }
+
+ // should not suggest since the trait is private
+ pub mod public_module {
+ trait OuterTrait {}
+ }
+}
--- /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.
+
+// testing whether the lookup mechanism picks up types
+// defined in the outside crate
+
+#![crate_type="lib"]
+
+mod foo {
+ // should not be suggested => foo is private
+ pub trait T {}
+}
+
+// should be suggested
+pub use foo::T;
--- /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.
+
+pub enum Homura {
+ Madoka { age: u32 }
+}
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub trait Foo {
+ fn bar();
+}
--- /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 enum Foo {
+ A,
+ B(isize),
+ C { a: isize },
+}
+
+impl Foo {
+ pub fn foo() {}
+ pub fn bar(&self) {}
+}
--- /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.
+
+// aux-build:namespaced_enums.rs
+extern crate namespaced_enums;
+
+fn main() {
+ let _ = namespaced_enums::A;
+ //~^ ERROR unresolved value `namespaced_enums::A`
+ //~| HELP you can import it into scope: `use namespaced_enums::Foo::A;`
+ let _ = namespaced_enums::B(10);
+ //~^ ERROR unresolved function `namespaced_enums::B`
+ //~| HELP you can import it into scope: `use namespaced_enums::Foo::B;`
+ let _ = namespaced_enums::C { a: 10 };
+ //~^ ERROR unresolved struct, variant or union type `namespaced_enums::C`
+ //~| HELP you can import it into scope: `use namespaced_enums::Foo::C;`
+}
--- /dev/null
+error[E0425]: unresolved value `namespaced_enums::A`
+ --> $DIR/enums-are-namespaced-xc.rs:15:13
+ |
+15 | let _ = namespaced_enums::A;
+ | ^^^^^^^^^^^^^^^^^^^ no resolution found
+ |
+ = help: possible candidate is found in another module, you can import it into scope:
+ = help: `use namespaced_enums::Foo::A;`
+
+error[E0425]: unresolved function `namespaced_enums::B`
+ --> $DIR/enums-are-namespaced-xc.rs:18:13
+ |
+18 | let _ = namespaced_enums::B(10);
+ | ^^^^^^^^^^^^^^^^^^^ no resolution found
+ |
+ = help: possible candidate is found in another module, you can import it into scope:
+ = help: `use namespaced_enums::Foo::B;`
+
+error[E0422]: unresolved struct, variant or union type `namespaced_enums::C`
+ --> $DIR/enums-are-namespaced-xc.rs:21:13
+ |
+21 | let _ = namespaced_enums::C { a: 10 };
+ | ^^^^^^^^^^^^^^^^^^^ no resolution found
+ |
+ = help: possible candidate is found in another module, you can import it into scope:
+ = help: `use namespaced_enums::Foo::C;`
+
+error: aborting due to 3 previous errors
+
--- /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.
+
+trait Foo {
+ fn bar(&self);
+ fn baz(&self) { }
+ fn bah(_: Option<&Self>) { }
+}
+
+struct BarTy {
+ x : isize,
+ y : f64,
+}
+
+impl BarTy {
+ fn a() {}
+ fn b(&self) {}
+}
+
+impl Foo for *const BarTy {
+ fn bar(&self) {
+ baz();
+ //~^ ERROR unresolved function `baz`
+ //~| NOTE did you mean `self.baz(...)`?
+ a;
+ //~^ ERROR unresolved value `a`
+ //~| NOTE no resolution found
+ }
+}
+
+impl<'a> Foo for &'a BarTy {
+ fn bar(&self) {
+ baz();
+ //~^ ERROR unresolved function `baz`
+ //~| NOTE did you mean `self.baz(...)`?
+ x;
+ //~^ ERROR unresolved value `x`
+ //~| NOTE did you mean `self.x`?
+ y;
+ //~^ ERROR unresolved value `y`
+ //~| NOTE did you mean `self.y`?
+ a;
+ //~^ ERROR unresolved value `a`
+ //~| NOTE no resolution found
+ bah;
+ //~^ ERROR unresolved value `bah`
+ //~| NOTE did you mean `Self::bah`?
+ b;
+ //~^ ERROR unresolved value `b`
+ //~| NOTE no resolution found
+ }
+}
+
+impl<'a> Foo for &'a mut BarTy {
+ fn bar(&self) {
+ baz();
+ //~^ ERROR unresolved function `baz`
+ //~| NOTE did you mean `self.baz(...)`?
+ x;
+ //~^ ERROR unresolved value `x`
+ //~| NOTE did you mean `self.x`?
+ y;
+ //~^ ERROR unresolved value `y`
+ //~| NOTE did you mean `self.y`?
+ a;
+ //~^ ERROR unresolved value `a`
+ //~| NOTE no resolution found
+ bah;
+ //~^ ERROR unresolved value `bah`
+ //~| NOTE did you mean `Self::bah`?
+ b;
+ //~^ ERROR unresolved value `b`
+ //~| NOTE no resolution found
+ }
+}
+
+impl Foo for Box<BarTy> {
+ fn bar(&self) {
+ baz();
+ //~^ ERROR unresolved function `baz`
+ //~| NOTE did you mean `self.baz(...)`?
+ bah;
+ //~^ ERROR unresolved value `bah`
+ //~| NOTE did you mean `Self::bah`?
+ }
+}
+
+impl Foo for *const isize {
+ fn bar(&self) {
+ baz();
+ //~^ ERROR unresolved function `baz`
+ //~| NOTE did you mean `self.baz(...)`?
+ bah;
+ //~^ ERROR unresolved value `bah`
+ //~| NOTE did you mean `Self::bah`?
+ }
+}
+
+impl<'a> Foo for &'a isize {
+ fn bar(&self) {
+ baz();
+ //~^ ERROR unresolved function `baz`
+ //~| NOTE did you mean `self.baz(...)`?
+ bah;
+ //~^ ERROR unresolved value `bah`
+ //~| NOTE did you mean `Self::bah`?
+ }
+}
+
+impl<'a> Foo for &'a mut isize {
+ fn bar(&self) {
+ baz();
+ //~^ ERROR unresolved function `baz`
+ //~| NOTE did you mean `self.baz(...)`?
+ bah;
+ //~^ ERROR unresolved value `bah`
+ //~| NOTE did you mean `Self::bah`?
+ }
+}
+
+impl Foo for Box<isize> {
+ fn bar(&self) {
+ baz();
+ //~^ ERROR unresolved function `baz`
+ //~| NOTE did you mean `self.baz(...)`?
+ bah;
+ //~^ ERROR unresolved value `bah`
+ //~| NOTE did you mean `Self::bah`?
+ }
+}
--- /dev/null
+error[E0425]: unresolved function `baz`
+ --> $DIR/issue-14254.rs:29:9
+ |
+29 | baz();
+ | ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `a`
+ --> $DIR/issue-14254.rs:32:9
+ |
+32 | a;
+ | ^ no resolution found
+
+error[E0425]: unresolved function `baz`
+ --> $DIR/issue-14254.rs:40:9
+ |
+40 | baz();
+ | ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `x`
+ --> $DIR/issue-14254.rs:43:9
+ |
+43 | x;
+ | ^ did you mean `self.x`?
+
+error[E0425]: unresolved value `y`
+ --> $DIR/issue-14254.rs:46:9
+ |
+46 | y;
+ | ^ did you mean `self.y`?
+
+error[E0425]: unresolved value `a`
+ --> $DIR/issue-14254.rs:49:9
+ |
+49 | a;
+ | ^ no resolution found
+
+error[E0425]: unresolved value `bah`
+ --> $DIR/issue-14254.rs:52:9
+ |
+52 | bah;
+ | ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved value `b`
+ --> $DIR/issue-14254.rs:55:9
+ |
+55 | b;
+ | ^ no resolution found
+
+error[E0425]: unresolved function `baz`
+ --> $DIR/issue-14254.rs:63:9
+ |
+63 | baz();
+ | ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `x`
+ --> $DIR/issue-14254.rs:66:9
+ |
+66 | x;
+ | ^ did you mean `self.x`?
+
+error[E0425]: unresolved value `y`
+ --> $DIR/issue-14254.rs:69:9
+ |
+69 | y;
+ | ^ did you mean `self.y`?
+
+error[E0425]: unresolved value `a`
+ --> $DIR/issue-14254.rs:72:9
+ |
+72 | a;
+ | ^ no resolution found
+
+error[E0425]: unresolved value `bah`
+ --> $DIR/issue-14254.rs:75:9
+ |
+75 | bah;
+ | ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved value `b`
+ --> $DIR/issue-14254.rs:78:9
+ |
+78 | b;
+ | ^ no resolution found
+
+error[E0425]: unresolved function `baz`
+ --> $DIR/issue-14254.rs:86:9
+ |
+86 | baz();
+ | ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+ --> $DIR/issue-14254.rs:89:9
+ |
+89 | bah;
+ | ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved function `baz`
+ --> $DIR/issue-14254.rs:97:9
+ |
+97 | baz();
+ | ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+ --> $DIR/issue-14254.rs:100:9
+ |
+100 | bah;
+ | ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved function `baz`
+ --> $DIR/issue-14254.rs:108:9
+ |
+108 | baz();
+ | ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+ --> $DIR/issue-14254.rs:111:9
+ |
+111 | bah;
+ | ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved function `baz`
+ --> $DIR/issue-14254.rs:119:9
+ |
+119 | baz();
+ | ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+ --> $DIR/issue-14254.rs:122:9
+ |
+122 | bah;
+ | ^^^ did you mean `Self::bah`?
+
+error[E0425]: unresolved function `baz`
+ --> $DIR/issue-14254.rs:130:9
+ |
+130 | baz();
+ | ^^^ did you mean `self.baz(...)`?
+
+error[E0425]: unresolved value `bah`
+ --> $DIR/issue-14254.rs:133:9
+ |
+133 | bah;
+ | ^^^ did you mean `Self::bah`?
+
+error: main function not found
+
+error: aborting due to 25 previous errors
+
--- /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.
+
+
+pub struct GslResult {
+ pub val: f64,
+ pub err: f64
+}
+
+impl GslResult {
+ pub fn new() -> GslResult {
+ Result {
+//~^ ERROR expected struct, variant or union type, found enum `Result`
+//~| HELP possible better candidates are found in other modules, you can import them into scope
+//~| HELP std::fmt::Result
+//~| HELP std::io::Result
+//~| HELP std::thread::Result
+ val: 0f64,
+ err: 0f64
+ }
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0574]: expected struct, variant or union type, found enum `Result`
+ --> $DIR/issue-16058.rs:19:9
+ |
+19 | Result {
+ | ^^^^^^ not a struct, variant or union type
+ |
+ = help: possible better candidates are found in other modules, you can import them into scope:
+ = help: `use std::fmt::Result;`
+ = help: `use std::io::Result;`
+ = help: `use std::thread::Result;`
+
+error: aborting due to previous error
+
--- /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.
+
+enum SomeEnum {
+ E
+}
+
+fn main() {
+ E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
+ //~^ HELP you can import it into scope: `use SomeEnum::E;`
+}
--- /dev/null
+error[E0422]: unresolved struct, variant or union type `E`
+ --> $DIR/issue-17518.rs:16:5
+ |
+16 | E { name: "foobar" }; //~ ERROR unresolved struct, variant or union type `E`
+ | ^ no resolution found
+ |
+ = help: possible candidate is found in another module, you can import it into scope:
+ = help: `use SomeEnum::E;`
+
+error: aborting due to previous error
+
--- /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.
+
+enum Foo {
+ Variant { x: usize }
+}
+
+fn main() {
+ let f = Foo::Variant(42);
+ //~^ ERROR expected function, found struct variant `Foo::Variant`
+}
--- /dev/null
+error[E0423]: expected function, found struct variant `Foo::Variant`
+ --> $DIR/issue-18252.rs:16:13
+ |
+16 | let f = Foo::Variant(42);
+ | ^^^^^^^^^^^^ did you mean `Foo::Variant { /* fields */ }`?
+
+error: aborting due to previous error
+
--- /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.
+
+// aux-build:issue_19452_aux.rs
+extern crate issue_19452_aux;
+
+enum Homura {
+ Madoka { age: u32 }
+}
+
+fn main() {
+ let homura = Homura::Madoka;
+ //~^ ERROR expected value, found struct variant `Homura::Madoka`
+
+ let homura = issue_19452_aux::Homura::Madoka;
+ //~^ ERROR expected value, found struct variant `issue_19452_aux::Homura::Madoka`
+}
--- /dev/null
+error[E0423]: expected value, found struct variant `Homura::Madoka`
+ --> $DIR/issue-19452.rs:19:18
+ |
+19 | let homura = Homura::Madoka;
+ | ^^^^^^^^^^^^^^ did you mean `Homura::Madoka { /* fields */ }`?
+
+error[E0423]: expected value, found struct variant `issue_19452_aux::Homura::Madoka`
+ --> $DIR/issue-19452.rs:22:18
+ |
+22 | let homura = issue_19452_aux::Homura::Madoka;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ did you mean `issue_19452_aux::Homura::Madoka { /* fields */ }`?
+
+error: aborting due to 2 previous errors
+
--- /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.
+
+mod mul1 {
+ pub trait Mul {}
+}
+
+mod mul2 {
+ pub trait Mul {}
+}
+
+mod mul3 {
+ enum Mul {
+ Yes,
+ No
+ }
+}
+
+mod mul4 {
+ type Mul = String;
+}
+
+mod mul5 {
+ struct Mul{
+ left_term: u32,
+ right_term: u32
+ }
+}
+
+#[derive(Debug)]
+struct Foo;
+
+// When we comment the next line:
+//use mul1::Mul;
+
+// BEFORE, we got the following error for the `impl` below:
+// error: use of undeclared trait name `Mul` [E0405]
+// AFTER, we get this message:
+// error: trait `Mul` is not in scope.
+// help: ...
+// help: you can import several candidates into scope (`use ...;`):
+// help: `mul1::Mul`
+// help: `mul2::Mul`
+// help: `std::ops::Mul`
+
+impl Mul for Foo {
+//~^ ERROR unresolved trait `Mul`
+//~| HELP possible candidates are found in other modules, you can import them into scope
+//~| HELP `mul1::Mul`
+//~| HELP `mul2::Mul`
+//~| HELP `std::ops::Mul`
+}
+
+// BEFORE, we got:
+// error: use of undeclared type name `Mul` [E0412]
+// AFTER, we get:
+// error: type name `Mul` is not in scope. Maybe you meant:
+// help: ...
+// help: you can import several candidates into scope (`use ...;`):
+// help: `mul1::Mul`
+// help: `mul2::Mul`
+// help: `mul3::Mul`
+// help: `mul4::Mul`
+// help: and 2 other candidates
+fn getMul() -> Mul {
+//~^ ERROR unresolved type `Mul`
+//~| HELP possible candidates are found in other modules, you can import them into scope
+//~| HELP `mul1::Mul`
+//~| HELP `mul2::Mul`
+//~| HELP `mul3::Mul`
+//~| HELP `mul4::Mul`
+//~| HELP and 2 other candidates
+}
+
+// Let's also test what happens if the trait doesn't exist:
+impl ThisTraitReallyDoesntExistInAnyModuleReally for Foo {
+//~^ ERROR unresolved trait `ThisTraitReallyDoesntExistInAnyModuleReally`
+}
+
+// Let's also test what happens if there's just one alternative:
+impl Div for Foo {
+//~^ ERROR unresolved trait `Div`
+//~| HELP `use std::ops::Div;`
+}
+
+fn main() {
+ let foo = Foo();
+ println!("Hello, {:?}!", foo);
+}
--- /dev/null
+error[E0405]: unresolved trait `Mul`
+ --> $DIR/issue-21221-1.rs:53:6
+ |
+53 | impl Mul for Foo {
+ | ^^^ no resolution found
+ |
+ = help: possible candidates are found in other modules, you can import them into scope:
+ = help: `use mul1::Mul;`
+ = help: `use mul2::Mul;`
+ = help: `use std::ops::Mul;`
+
+error[E0412]: unresolved type `Mul`
+ --> $DIR/issue-21221-1.rs:72:16
+ |
+72 | fn getMul() -> Mul {
+ | ^^^ no resolution found
+ |
+ = help: possible candidates are found in other modules, you can import them into scope:
+ = help: `use mul1::Mul;`
+ = help: `use mul2::Mul;`
+ = help: `use mul3::Mul;`
+ = help: `use mul4::Mul;`
+ = help: and 2 other candidates
+
+error[E0405]: unresolved trait `ThisTraitReallyDoesntExistInAnyModuleReally`
+ --> $DIR/issue-21221-1.rs:83:6
+ |
+83 | impl ThisTraitReallyDoesntExistInAnyModuleReally for Foo {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no resolution found
+
+error[E0405]: unresolved trait `Div`
+ --> $DIR/issue-21221-1.rs:88:6
+ |
+88 | impl Div for Foo {
+ | ^^^ no resolution found
+ |
+ = help: possible candidate is found in another module, you can import it into scope:
+ = help: `use std::ops::Div;`
+
+error: cannot continue compilation due to previous error
+
--- /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.
+
+pub mod foo {
+ pub mod bar {
+ // note: trait T is not public, but being in the current
+ // crate, it's fine to show it, since the programmer can
+ // decide to make it public based on the suggestion ...
+ pub trait T {}
+ }
+ // imports should be ignored:
+ use self::bar::T;
+}
+
+pub mod baz {
+ pub use foo;
+ pub use std::ops::{Mul as T};
+}
+
+struct Foo;
+impl T for Foo { }
+//~^ ERROR unresolved trait `T`
+//~| HELP you can import it into scope: `use foo::bar::T;`
--- /dev/null
+error[E0405]: unresolved trait `T`
+ --> $DIR/issue-21221-2.rs:28:6
+ |
+28 | impl T for Foo { }
+ | ^ no resolution found
+ |
+ = help: possible candidate is found in another module, you can import it into scope:
+ = help: `use foo::bar::T;`
+
+error: main function not found
+
+error: cannot continue compilation due to previous error
+
--- /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.
+
+// testing whether the lookup mechanism picks up types
+// defined in the outside crate
+
+// aux-build:issue-21221-3.rs
+
+extern crate issue_21221_3;
+
+struct Foo;
+
+// NOTE: This shows only traits accessible from the current
+// crate, thus the two private entities:
+// `issue_21221_3::outer::private_module::OuterTrait` and
+// `issue_21221_3::outer::public_module::OuterTrait`
+// are hidden from the view.
+impl OuterTrait for Foo {}
+//~^ ERROR unresolved trait `OuterTrait`
+//~| HELP you can import it into scope: `use issue_21221_3::outer::OuterTrait;`
+fn main() {
+ println!("Hello, world!");
+}
--- /dev/null
+error[E0405]: unresolved trait `OuterTrait`
+ --> $DIR/issue-21221-3.rs:25:6
+ |
+25 | impl OuterTrait for Foo {}
+ | ^^^^^^^^^^ no resolution found
+ |
+ = help: possible candidate is found in another module, you can import it into scope:
+ = help: `use issue_21221_3::outer::OuterTrait;`
+
+error: cannot continue compilation due to previous error
+
--- /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.
+
+// testing whether the lookup mechanism picks up types
+// defined in the outside crate
+
+// aux-build:issue-21221-4.rs
+
+extern crate issue_21221_4;
+
+struct Foo;
+
+impl T for Foo {}
+//~^ ERROR unresolved trait `T`
+//~| HELP you can import it into scope: `use issue_21221_4::T;`
+
+fn main() {
+ println!("Hello, world!");
+}
--- /dev/null
+error[E0405]: unresolved trait `T`
+ --> $DIR/issue-21221-4.rs:20:6
+ |
+20 | impl T for Foo {}
+ | ^ no resolution found
+ |
+ = help: possible candidate is found in another module, you can import it into scope:
+ = help: `use issue_21221_4::T;`
+
+error: cannot continue compilation due to previous error
+
--- /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.
+
+pub trait ToNbt<T> {
+ fn new(val: T) -> Self;
+}
+
+impl ToNbt<Self> {}
+//~^ ERROR unresolved type `Self`
+//~| NOTE `Self` is only available in traits and impls
+//~| ERROR the trait `ToNbt` cannot be made into an object
+//~| NOTE the trait `ToNbt` cannot be made into an object
+//~| NOTE method `new` has no receiver
+
+fn main() {}
--- /dev/null
+error[E0411]: unresolved type `Self`
+ --> $DIR/issue-23305.rs:15:12
+ |
+15 | impl ToNbt<Self> {}
+ | ^^^^ `Self` is only available in traits and impls
+
+error[E0038]: the trait `ToNbt` cannot be made into an object
+ --> $DIR/issue-23305.rs:15:6
+ |
+15 | impl ToNbt<Self> {}
+ | ^^^^^^^^^^^ the trait `ToNbt` cannot be made into an object
+ |
+ = note: method `new` has no receiver
+
+error: aborting due to previous error
+
--- /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.
+
+trait Groom {
+ fn shave(other: usize);
+}
+
+pub struct cat {
+ whiskers: isize,
+}
+
+pub enum MaybeDog {
+ Dog,
+ NoDog
+}
+
+impl MaybeDog {
+ fn bark() {
+ // If this provides a suggestion, it's a bug as MaybeDog doesn't impl Groom
+ shave();
+ //~^ ERROR unresolved function `shave`
+ //~| NOTE no resolution found
+ }
+}
+
+impl Clone for cat {
+ fn clone(&self) -> Self {
+ clone();
+ //~^ ERROR unresolved function `clone`
+ //~| NOTE did you mean `self.clone(...)`?
+ loop {}
+ }
+}
+impl Default for cat {
+ fn default() -> Self {
+ default();
+ //~^ ERROR unresolved function `default`
+ //~| NOTE did you mean `Self::default`?
+ loop {}
+ }
+}
+
+impl Groom for cat {
+ fn shave(other: usize) {
+ whiskers -= other;
+ //~^ ERROR unresolved value `whiskers`
+ //~| ERROR unresolved value `whiskers`
+ //~| NOTE did you mean `self.whiskers`?
+ //~| NOTE `self` value is only available in methods with `self` parameter
+ shave(4);
+ //~^ ERROR unresolved function `shave`
+ //~| NOTE did you mean `Self::shave`?
+ purr();
+ //~^ ERROR unresolved function `purr`
+ //~| NOTE no resolution found
+ }
+}
+
+impl cat {
+ fn static_method() {}
+
+ fn purr_louder() {
+ static_method();
+ //~^ ERROR unresolved function `static_method`
+ //~| NOTE no resolution found
+ purr();
+ //~^ ERROR unresolved function `purr`
+ //~| NOTE no resolution found
+ purr();
+ //~^ ERROR unresolved function `purr`
+ //~| NOTE no resolution found
+ purr();
+ //~^ ERROR unresolved function `purr`
+ //~| NOTE no resolution found
+ }
+}
+
+impl cat {
+ fn meow() {
+ if self.whiskers > 3 {
+ //~^ ERROR expected value, found module `self`
+ //~| NOTE `self` value is only available in methods with `self` parameter
+ println!("MEOW");
+ }
+ }
+
+ fn purr(&self) {
+ grow_older();
+ //~^ ERROR unresolved function `grow_older`
+ //~| NOTE no resolution found
+ shave();
+ //~^ ERROR unresolved function `shave`
+ //~| NOTE no resolution found
+ }
+
+ fn burn_whiskers(&mut self) {
+ whiskers = 0;
+ //~^ ERROR unresolved value `whiskers`
+ //~| NOTE did you mean `self.whiskers`?
+ }
+
+ pub fn grow_older(other:usize) {
+ whiskers = 4;
+ //~^ ERROR unresolved value `whiskers`
+ //~| ERROR unresolved value `whiskers`
+ //~| NOTE did you mean `self.whiskers`?
+ //~| NOTE `self` value is only available in methods with `self` parameter
+ purr_louder();
+ //~^ ERROR unresolved function `purr_louder`
+ //~| NOTE no resolution found
+ }
+}
+
+fn main() {
+ self += 1;
+ //~^ ERROR expected value, found module `self`
+ //~| NOTE `self` value is only available in methods with `self` parameter
+}
--- /dev/null
+error[E0425]: unresolved function `shave`
+ --> $DIR/issue-2356.rs:27:5
+ |
+27 | shave();
+ | ^^^^^ no resolution found
+
+error[E0425]: unresolved function `clone`
+ --> $DIR/issue-2356.rs:35:5
+ |
+35 | clone();
+ | ^^^^^ did you mean `self.clone(...)`?
+
+error[E0425]: unresolved function `default`
+ --> $DIR/issue-2356.rs:43:5
+ |
+43 | default();
+ | ^^^^^^^ did you mean `Self::default`?
+
+error[E0425]: unresolved value `whiskers`
+ --> $DIR/issue-2356.rs:52:5
+ |
+52 | whiskers -= other;
+ | ^^^^^^^^
+ | |
+ | did you mean `self.whiskers`?
+ | `self` value is only available in methods with `self` parameter
+
+error[E0425]: unresolved function `shave`
+ --> $DIR/issue-2356.rs:57:5
+ |
+57 | shave(4);
+ | ^^^^^ did you mean `Self::shave`?
+
+error[E0425]: unresolved function `purr`
+ --> $DIR/issue-2356.rs:60:5
+ |
+60 | purr();
+ | ^^^^ no resolution found
+
+error[E0425]: unresolved function `static_method`
+ --> $DIR/issue-2356.rs:70:9
+ |
+70 | static_method();
+ | ^^^^^^^^^^^^^ no resolution found
+
+error[E0425]: unresolved function `purr`
+ --> $DIR/issue-2356.rs:73:9
+ |
+73 | purr();
+ | ^^^^ no resolution found
+
+error[E0425]: unresolved function `purr`
+ --> $DIR/issue-2356.rs:76:9
+ |
+76 | purr();
+ | ^^^^ no resolution found
+
+error[E0425]: unresolved function `purr`
+ --> $DIR/issue-2356.rs:79:9
+ |
+79 | purr();
+ | ^^^^ no resolution found
+
+error[E0424]: expected value, found module `self`
+ --> $DIR/issue-2356.rs:87:8
+ |
+87 | if self.whiskers > 3 {
+ | ^^^^ `self` value is only available in methods with `self` parameter
+
+error[E0425]: unresolved function `grow_older`
+ --> $DIR/issue-2356.rs:95:5
+ |
+95 | grow_older();
+ | ^^^^^^^^^^ no resolution found
+
+error[E0425]: unresolved function `shave`
+ --> $DIR/issue-2356.rs:98:5
+ |
+98 | shave();
+ | ^^^^^ no resolution found
+
+error[E0425]: unresolved value `whiskers`
+ --> $DIR/issue-2356.rs:104:5
+ |
+104 | whiskers = 0;
+ | ^^^^^^^^ did you mean `self.whiskers`?
+
+error[E0425]: unresolved value `whiskers`
+ --> $DIR/issue-2356.rs:110:5
+ |
+110 | whiskers = 4;
+ | ^^^^^^^^
+ | |
+ | did you mean `self.whiskers`?
+ | `self` value is only available in methods with `self` parameter
+
+error[E0425]: unresolved function `purr_louder`
+ --> $DIR/issue-2356.rs:115:5
+ |
+115 | purr_louder();
+ | ^^^^^^^^^^^ no resolution found
+
+error[E0424]: expected value, found module `self`
+ --> $DIR/issue-2356.rs:122:5
+ |
+122 | self += 1;
+ | ^^^^ `self` value is only available in methods with `self` parameter
+
+error: aborting due to 17 previous errors
+
--- /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.
+
+fn foo(_: Self) {
+//~^ ERROR unresolved type `Self`
+//~| NOTE `Self` is only available in traits and impls
+}
+
+fn main() {}
--- /dev/null
+error[E0411]: unresolved type `Self`
+ --> $DIR/issue-24968.rs:11:11
+ |
+11 | fn foo(_: Self) {
+ | ^^^^ `Self` is only available in traits and impls
+
+error: aborting due to previous error
+
--- /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 std::any::Any;
+
+struct Foo;
+
+trait Bar {}
+
+impl Bar for Foo {}
+
+fn main() {
+ let any: &Any = &Bar; //~ ERROR expected value, found trait `Bar`
+ if any.is::<u32>() { println!("u32"); }
+}
--- /dev/null
+error[E0423]: expected value, found trait `Bar`
+ --> $DIR/issue-33876.rs:20:22
+ |
+20 | let any: &Any = &Bar; //~ ERROR expected value, found trait `Bar`
+ | ^^^ not a value
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2013-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.
+
+// aux-build:issue_3907.rs
+extern crate issue_3907;
+
+type Foo = issue_3907::Foo+'static;
+
+struct S {
+ name: isize
+}
+
+fn bar(_x: Foo) {}
+//~^ ERROR E0038
+
+fn main() {}
--- /dev/null
+error[E0038]: the trait `issue_3907::Foo` cannot be made into an object
+ --> $DIR/issue-3907-2.rs:20:1
+ |
+20 | fn bar(_x: Foo) {}
+ | ^^^^^^^^^^^^^^^^^^ the trait `issue_3907::Foo` cannot be made into an object
+ |
+ = note: method `bar` has no receiver
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2013-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.
+
+// aux-build:issue_3907.rs
+extern crate issue_3907;
+
+type Foo = issue_3907::Foo;
+
+struct S {
+ name: isize
+}
+
+impl Foo for S { //~ ERROR expected trait, found type alias `Foo`
+ fn bar() { }
+}
+
+fn main() {
+ let s = S {
+ name: 0
+ };
+ s.bar();
+}
--- /dev/null
+error[E0404]: expected trait, found type alias `Foo`
+ --> $DIR/issue-3907.rs:20:6
+ |
+20 | impl Foo for S { //~ ERROR expected trait, found type alias `Foo`
+ | ^^^ type aliases cannot be used for traits
+ |
+ = help: possible better candidate is found in another module, you can import it into scope:
+ = help: `use issue_3907::Foo;`
+
+error: cannot continue compilation due to previous error
+
--- /dev/null
+// Copyright 2013-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.
+
+trait I {}
+type K = I+'static;
+
+fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied
+
+fn main() {}
--- /dev/null
+error[E0277]: the trait bound `I + 'static: std::marker::Sized` is not satisfied
+ --> $DIR/issue-5035-2.rs:14:8
+ |
+14 | fn foo(_x: K) {} //~ ERROR: `I + 'static: std::marker::Sized` is not satisfied
+ | ^^ the trait `std::marker::Sized` is not implemented for `I + 'static`
+ |
+ = note: `I + 'static` does not have a constant size known at compile-time
+ = note: all local variables must have a statically known size
+
+error: aborting due to previous error
+
--- /dev/null
+// Copyright 2013-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.
+
+trait I {}
+type K = I;
+impl K for isize {} //~ ERROR expected trait, found type alias `K`
+ //~| NOTE type aliases cannot be used for traits
+
+use ImportError; //~ ERROR unresolved import `ImportError` [E0432]
+ //~^ no `ImportError` in the root
+impl ImportError for () {} // check that this is not an additional error (c.f. #35142)
+
+fn main() {}
--- /dev/null
+error[E0432]: unresolved import `ImportError`
+ --> $DIR/issue-5035.rs:16:5
+ |
+16 | use ImportError; //~ ERROR unresolved import `ImportError` [E0432]
+ | ^^^^^^^^^^^ no `ImportError` in the root
+
+error[E0404]: expected trait, found type alias `K`
+ --> $DIR/issue-5035.rs:13:6
+ |
+13 | impl K for isize {} //~ ERROR expected trait, found type alias `K`
+ | ^ type aliases cannot be used for traits
+
+error: cannot continue compilation due to previous error
+
--- /dev/null
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Monster {
+ damage: isize
+}
+
+
+fn main() {
+ let _m = Monster(); //~ ERROR expected function, found struct `Monster`
+ //~^ NOTE did you mean `Monster { /* fields */ }`?
+}
--- /dev/null
+error[E0423]: expected function, found struct `Monster`
+ --> $DIR/issue-6702.rs:17:14
+ |
+17 | let _m = Monster(); //~ ERROR expected function, found struct `Monster`
+ | ^^^^^^^ did you mean `Monster { /* fields */ }`?
+
+error: aborting due to previous error
+
--- /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.
+
+// Make sure associated items are recommended only in appropriate contexts.
+
+struct S {
+ field: u8,
+}
+
+trait Tr {
+ fn method(&self);
+ type Type;
+}
+
+impl Tr for S {
+ type Type = u8;
+
+ fn method(&self) {
+ let _: field;
+ //~^ ERROR unresolved type `field`
+ //~| NOTE no resolution found
+ let field(..);
+ //~^ ERROR unresolved tuple struct/variant `field`
+ //~| NOTE no resolution found
+ field;
+ //~^ ERROR unresolved value `field`
+ //~| NOTE did you mean `self.field`?
+
+ let _: Type;
+ //~^ ERROR unresolved type `Type`
+ //~| NOTE did you mean `Self::Type`?
+ let Type(..);
+ //~^ ERROR unresolved tuple struct/variant `Type`
+ //~| NOTE no resolution found
+ Type;
+ //~^ ERROR unresolved value `Type`
+ //~| NOTE no resolution found
+
+ let _: method;
+ //~^ ERROR unresolved type `method`
+ //~| NOTE no resolution found
+ let method(..);
+ //~^ ERROR unresolved tuple struct/variant `method`
+ //~| NOTE no resolution found
+ method;
+ //~^ ERROR unresolved value `method`
+ //~| NOTE did you mean `self.method(...)`?
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0412]: unresolved type `field`
+ --> $DIR/resolve-assoc-suggestions.rs:26:16
+ |
+26 | let _: field;
+ | ^^^^^ no resolution found
+
+error[E0531]: unresolved tuple struct/variant `field`
+ --> $DIR/resolve-assoc-suggestions.rs:29:13
+ |
+29 | let field(..);
+ | ^^^^^ no resolution found
+
+error[E0425]: unresolved value `field`
+ --> $DIR/resolve-assoc-suggestions.rs:32:9
+ |
+32 | field;
+ | ^^^^^ did you mean `self.field`?
+
+error[E0412]: unresolved type `Type`
+ --> $DIR/resolve-assoc-suggestions.rs:36:16
+ |
+36 | let _: Type;
+ | ^^^^ did you mean `Self::Type`?
+
+error[E0531]: unresolved tuple struct/variant `Type`
+ --> $DIR/resolve-assoc-suggestions.rs:39:13
+ |
+39 | let Type(..);
+ | ^^^^ no resolution found
+
+error[E0425]: unresolved value `Type`
+ --> $DIR/resolve-assoc-suggestions.rs:42:9
+ |
+42 | Type;
+ | ^^^^ no resolution found
+
+error[E0412]: unresolved type `method`
+ --> $DIR/resolve-assoc-suggestions.rs:46:16
+ |
+46 | let _: method;
+ | ^^^^^^ no resolution found
+
+error[E0531]: unresolved tuple struct/variant `method`
+ --> $DIR/resolve-assoc-suggestions.rs:49:13
+ |
+49 | let method(..);
+ | ^^^^^^ no resolution found
+
+error[E0425]: unresolved value `method`
+ --> $DIR/resolve-assoc-suggestions.rs:52:9
+ |
+52 | method;
+ | ^^^^^^ did you mean `self.method(...)`?
+
+error: aborting due to 9 previous errors
+
--- /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.
+
+fn main() {
+ assert(true);
+ //~^ ERROR expected function, found macro `assert`
+ //~| NOTE did you mean `assert!(...)`?
+}
--- /dev/null
+error[E0423]: expected function, found macro `assert`
+ --> $DIR/resolve-hint-macro.rs:12:5
+ |
+12 | assert(true);
+ | ^^^^^^ did you mean `assert!(...)`?
+
+error: aborting due to previous error
+
--- /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.
+
+// Make sure speculative path resolution works properly when resolution
+// adjustment happens and no extra errors is reported.
+
+struct S {
+ field: u8,
+}
+
+trait Tr {
+ fn method(&self);
+}
+
+impl Tr for S {
+ fn method(&self) {
+ fn g() {
+ // Speculative resolution of `Self` and `self` silently fails,
+ // "did you mean" messages are not printed.
+ field;
+ //~^ ERROR unresolved value `field`
+ //~| NOTE no resolution found
+ method();
+ //~^ ERROR unresolved function `method`
+ //~| NOTE no resolution found
+ }
+
+ field;
+ //~^ ERROR unresolved value `field`
+ //~| NOTE did you mean `self.field`?
+ method();
+ //~^ ERROR unresolved function `method`
+ //~| NOTE did you mean `self.method(...)`?
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0425]: unresolved value `field`
+ --> $DIR/resolve-speculative-adjustment.rs:27:13
+ |
+27 | field;
+ | ^^^^^ no resolution found
+
+error[E0425]: unresolved function `method`
+ --> $DIR/resolve-speculative-adjustment.rs:30:13
+ |
+30 | method();
+ | ^^^^^^ no resolution found
+
+error[E0425]: unresolved value `field`
+ --> $DIR/resolve-speculative-adjustment.rs:35:9
+ |
+35 | field;
+ | ^^^^^ did you mean `self.field`?
+
+error[E0425]: unresolved function `method`
+ --> $DIR/resolve-speculative-adjustment.rs:38:9
+ |
+38 | method();
+ | ^^^^^^ did you mean `self.method(...)`?
+
+error: aborting due to 4 previous errors
+
--- /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.
+
+// Beginners write `mod.item` when they should write `mod::item`.
+// This tests that we suggest the latter when we encounter the former.
+
+pub mod a {
+ pub const I: i32 = 1;
+
+ pub fn f() -> i32 { 2 }
+
+ pub mod b {
+ pub const J: i32 = 3;
+
+ pub fn g() -> i32 { 4 }
+ }
+}
+
+fn h1() -> i32 {
+ a.I
+ //~^ ERROR expected value, found module `a`
+ //~| NOTE did you mean `a::I`?
+}
+
+fn h2() -> i32 {
+ a.g()
+ //~^ ERROR expected value, found module `a`
+ //~| NOTE did you mean `a::g(...)`?
+}
+
+fn h3() -> i32 {
+ a.b.J
+ //~^ ERROR expected value, found module `a`
+ //~| NOTE did you mean `a::b`?
+}
+
+fn h4() -> i32 {
+ a::b.J
+ //~^ ERROR expected value, found module `a::b`
+ //~| NOTE did you mean `a::b::J`?
+}
+
+fn h5() {
+ a.b.f();
+ //~^ ERROR expected value, found module `a`
+ //~| NOTE did you mean `a::b`?
+ let v = Vec::new();
+ v.push(a::b);
+ //~^ ERROR expected value, found module `a::b`
+ //~| NOTE not a value
+}
+
+fn h6() -> i32 {
+ a::b.f()
+ //~^ ERROR expected value, found module `a::b`
+ //~| NOTE did you mean `a::b::f(...)`?
+}
+
+fn h7() {
+ a::b
+ //~^ ERROR expected value, found module `a::b`
+ //~| NOTE not a value
+}
+
+fn h8() -> i32 {
+ a::b()
+ //~^ ERROR expected function, found module `a::b`
+ //~| NOTE not a function
+}
--- /dev/null
+error[E0423]: expected value, found module `a`
+ --> $DIR/suggest-path-instead-of-mod-dot-item.rs:27:5
+ |
+27 | a.I
+ | ^ did you mean `a::I`?
+
+error[E0423]: expected value, found module `a`
+ --> $DIR/suggest-path-instead-of-mod-dot-item.rs:33:5
+ |
+33 | a.g()
+ | ^ did you mean `a::g(...)`?
+
+error[E0423]: expected value, found module `a`
+ --> $DIR/suggest-path-instead-of-mod-dot-item.rs:39:5
+ |
+39 | a.b.J
+ | ^ did you mean `a::b`?
+
+error[E0423]: expected value, found module `a::b`
+ --> $DIR/suggest-path-instead-of-mod-dot-item.rs:45:5
+ |
+45 | a::b.J
+ | ^^^^ did you mean `a::b::J`?
+
+error[E0423]: expected value, found module `a`
+ --> $DIR/suggest-path-instead-of-mod-dot-item.rs:51:5
+ |
+51 | a.b.f();
+ | ^ did you mean `a::b`?
+
+error[E0423]: expected value, found module `a::b`
+ --> $DIR/suggest-path-instead-of-mod-dot-item.rs:55:12
+ |
+55 | v.push(a::b);
+ | ^^^^ not a value
+
+error[E0423]: expected value, found module `a::b`
+ --> $DIR/suggest-path-instead-of-mod-dot-item.rs:61:5
+ |
+61 | a::b.f()
+ | ^^^^ did you mean `a::b::f(...)`?
+
+error[E0423]: expected value, found module `a::b`
+ --> $DIR/suggest-path-instead-of-mod-dot-item.rs:67:5
+ |
+67 | a::b
+ | ^^^^ not a value
+
+error[E0423]: expected function, found module `a::b`
+ --> $DIR/suggest-path-instead-of-mod-dot-item.rs:73:5
+ |
+73 | a::b()
+ | ^^^^ not a function
+
+error: main function not found
+
+error: aborting due to 10 previous errors
+
--- /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.
+
+// Test that we do some basic error correcton in the tokeniser (and don't ICE).
+
+fn main() {
+ if foo {
+ //~^ NOTE: unclosed delimiter
+ //~| ERROR: unresolved value `foo`
+ //~| NOTE: no resolution found
+ ) //~ ERROR: incorrect close delimiter: `)`
+}
--- /dev/null
+error: incorrect close delimiter: `)`
+ --> $DIR/token-error-correct-2.rs:18:5
+ |
+18 | ) //~ ERROR: incorrect close delimiter: `)`
+ | ^
+ |
+note: unclosed delimiter
+ --> $DIR/token-error-correct-2.rs:14:12
+ |
+14 | if foo {
+ | ^
+
+error[E0425]: unresolved value `foo`
+ --> $DIR/token-error-correct-2.rs:14:8
+ |
+14 | if foo {
+ | ^^^ no resolution found
+
+error: aborting due to 2 previous errors
+
--- /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.
+
+// Test that we do some basic error correcton in the tokeniser (and don't spew
+// too many bogus errors).
+
+pub mod raw {
+ use std::{io, fs};
+ use std::path::Path;
+
+ pub fn ensure_dir_exists<P: AsRef<Path>, F: FnOnce(&Path)>(path: P,
+ callback: F)
+ -> io::Result<bool> {
+ if !is_directory(path.as_ref()) { //~ ERROR: unresolved function `is_directory`
+ //~^ NOTE: no resolution found
+ callback(path.as_ref(); //~ NOTE: unclosed delimiter
+ //~^ ERROR: expected one of
+ fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
+ //~^ expected (), found enum `std::result::Result`
+ //~| expected type `()`
+ //~| found type `std::result::Result<bool, std::io::Error>`
+ } else { //~ ERROR: incorrect close delimiter: `}`
+ //~^ ERROR: expected one of
+ Ok(false);
+ }
+
+ panic!();
+ }
+}
+
+fn main() {}
--- /dev/null
+error: incorrect close delimiter: `}`
+ --> $DIR/token-error-correct-3.rs:29:9
+ |
+29 | } else { //~ ERROR: incorrect close delimiter: `}`
+ | ^
+ |
+note: unclosed delimiter
+ --> $DIR/token-error-correct-3.rs:23:21
+ |
+23 | callback(path.as_ref(); //~ NOTE: unclosed delimiter
+ | ^
+
+error: expected one of `,`, `.`, `?`, or an operator, found `;`
+ --> $DIR/token-error-correct-3.rs:23:35
+ |
+23 | callback(path.as_ref(); //~ NOTE: unclosed delimiter
+ | ^
+
+error: expected one of `.`, `;`, `?`, `}`, or an operator, found `)`
+ --> $DIR/token-error-correct-3.rs:29:9
+ |
+29 | } else { //~ ERROR: incorrect close delimiter: `}`
+ | ^
+
+error[E0425]: unresolved function `is_directory`
+ --> $DIR/token-error-correct-3.rs:21:13
+ |
+21 | if !is_directory(path.as_ref()) { //~ ERROR: unresolved function `is_directory`
+ | ^^^^^^^^^^^^ no resolution found
+
+error[E0308]: mismatched types
+ --> $DIR/token-error-correct-3.rs:25:13
+ |
+25 | fs::create_dir_all(path.as_ref()).map(|()| true) //~ ERROR: mismatched types
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), found enum `std::result::Result`
+ |
+ = note: expected type `()`
+ = note: found type `std::result::Result<bool, std::io::Error>`
+ = help: here are some functions which might fulfill your needs:
+ - .unwrap()
+ - .unwrap_err()
+ - .unwrap_or_default()
+
+error: aborting due to previous error
+
--- /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.
+
+// Test that we do some basic error correcton in the tokeniser.
+
+fn main() {
+ foo(bar(;
+ //~^ NOTE: unclosed delimiter
+ //~| NOTE: unclosed delimiter
+ //~| ERROR: expected expression, found `;`
+ //~| ERROR: unresolved function `foo`
+ //~| NOTE: no resolution found
+ //~| ERROR: unresolved function `bar`
+ //~| NOTE: no resolution found
+ //~| ERROR: expected one of `)`, `,`, `.`, `<`, `?`
+}
+//~^ ERROR: incorrect close delimiter: `}`
+//~| ERROR: incorrect close delimiter: `}`
+//~| ERROR: expected expression, found `)`
--- /dev/null
+error: incorrect close delimiter: `}`
+ --> $DIR/token-error-correct.rs:23:1
+ |
+23 | }
+ | ^
+ |
+note: unclosed delimiter
+ --> $DIR/token-error-correct.rs:14:12
+ |
+14 | foo(bar(;
+ | ^
+
+error: incorrect close delimiter: `}`
+ --> $DIR/token-error-correct.rs:23:1
+ |
+23 | }
+ | ^
+ |
+note: unclosed delimiter
+ --> $DIR/token-error-correct.rs:14:8
+ |
+14 | foo(bar(;
+ | ^
+
+error: expected expression, found `;`
+ --> $DIR/token-error-correct.rs:14:13
+ |
+14 | foo(bar(;
+ | ^
+
+error: expected one of `)`, `,`, `.`, `<`, `?`, `break`, `continue`, `false`, `for`, `if`, `loop`, `match`, `move`, `return`, `true`, `unsafe`, `while`, or an operator, found `;`
+ --> $DIR/token-error-correct.rs:14:13
+ |
+14 | foo(bar(;
+ | ^
+
+error: expected expression, found `)`
+ --> $DIR/token-error-correct.rs:23:1
+ |
+23 | }
+ | ^
+
+error[E0425]: unresolved function `foo`
+ --> $DIR/token-error-correct.rs:14:5
+ |
+14 | foo(bar(;
+ | ^^^ no resolution found
+
+error[E0425]: unresolved function `bar`
+ --> $DIR/token-error-correct.rs:14:9
+ |
+14 | foo(bar(;
+ | ^^^ no resolution found
+
+error: aborting due to 7 previous errors
+
--- /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 S(u8, u16);
+type A = S;
+
+impl S {
+ fn f() {
+ let s = Self(0, 1);
+ match s {
+ Self(..) => {}
+ }
+ }
+}
+
+fn main() {
+ let s = A(0, 1);
+ match s {
+ A(..) => {}
+ }
+}
--- /dev/null
+error[E0423]: expected function, found self type `Self`
+ --> $DIR/tuple-struct-alias.rs:16:17
+ |
+16 | let s = Self(0, 1);
+ | ^^^^ did you mean `Self { /* fields */ }`?
+
+error[E0532]: expected tuple struct/variant, found self type `Self`
+ --> $DIR/tuple-struct-alias.rs:18:13
+ |
+18 | Self(..) => {}
+ | ^^^^ did you mean `Self { /* fields */ }`?
+
+error[E0423]: expected function, found type alias `A`
+ --> $DIR/tuple-struct-alias.rs:24:13
+ |
+24 | let s = A(0, 1);
+ | ^ did you mean `A { /* fields */ }`?
+
+error[E0532]: expected tuple struct/variant, found type alias `A`
+ --> $DIR/tuple-struct-alias.rs:26:9
+ |
+26 | A(..) => {}
+ | ^ did you mean `A { /* fields */ }`?
+
+error: aborting due to 4 previous errors
+
--- /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.
+
+fn f<F:Nonexist(isize) -> isize>(x: F) {}
+//~^ ERROR unresolved trait `Nonexist`
+//~| NOTE no resolution found
+
+type Typedef = isize;
+
+fn g<F:Typedef(isize) -> isize>(x: F) {}
+//~^ ERROR expected trait, found type alias `Typedef`
+//~| NOTE type aliases cannot be used for traits
+
+fn main() {}
--- /dev/null
+error[E0405]: unresolved trait `Nonexist`
+ --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:11:8
+ |
+11 | fn f<F:Nonexist(isize) -> isize>(x: F) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ no resolution found
+
+error[E0404]: expected trait, found type alias `Typedef`
+ --> $DIR/unboxed-closure-sugar-nonexistent-trait.rs:17:8
+ |
+17 | fn g<F:Typedef(isize) -> isize>(x: F) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ type aliases cannot be used for traits
+
+error: cannot continue compilation due to previous error
+
--- /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.
+
+fn f(_: bool) {}
+
+struct Foo {
+ cx: bool,
+}
+
+impl Foo {
+ fn bar() {
+ f(cx);
+ //~^ ERROR unresolved value `cx`
+ //~| ERROR unresolved value `cx`
+ //~| NOTE did you mean `self.cx`?
+ //~| NOTE `self` value is only available in methods with `self` parameter
+ }
+}
+
+fn main() {}
--- /dev/null
+error[E0425]: unresolved value `cx`
+ --> $DIR/unresolved_static_type_field.rs:19:11
+ |
+19 | f(cx);
+ | ^^
+ | |
+ | did you mean `self.cx`?
+ | `self` value is only available in methods with `self` parameter
+
+error: aborting due to previous error
+
+error[E0437]: type `bar` is not a member of trait `Foo`
+ --> $DIR/impl-wrong-item-for-trait.rs:47:5
+ |
+47 | type bar = u64;
+ | ^^^^^^^^^^^^^^^ not a member of trait `Foo`
+
error[E0323]: item `bar` is an associated const, which doesn't match its trait `Foo`
--> $DIR/impl-wrong-item-for-trait.rs:25:5
|
-error[E0404]: `Add` is not a trait
+error[E0404]: expected trait, found type parameter `Add`
--> $DIR/issue-35987.rs:15:21
|
15 | impl<T: Clone, Add> Add for Foo<T> {
- | --- ^^^ expected trait, found type parameter
- | |
- | type parameter defined here
+ | ^^^ not a trait
+ |
+ = help: possible better candidate is found in another module, you can import it into scope:
+ = help: `use std::ops::Add;`
error: main function not found
-error: cannot borrow immutable borrowed content `*a` as mutable
- --> $DIR/mut-arg-hint.rs:13:9
- |
-12 | fn foo(mut a: &String) {
- | ------- use `&mut String` here to make mutable
-13 | a.push_str("bar");
- | ^
-
error: cannot borrow immutable borrowed content `*a` as mutable
--> $DIR/mut-arg-hint.rs:18:5
|
18 | a.push_str("foo");
| ^
+error: cannot borrow immutable borrowed content `*a` as mutable
+ --> $DIR/mut-arg-hint.rs:13:9
+ |
+12 | fn foo(mut a: &String) {
+ | ------- use `&mut String` here to make mutable
+13 | a.push_str("bar");
+ | ^
+
error: cannot borrow immutable borrowed content `*a` as mutable
--> $DIR/mut-arg-hint.rs:25:9
|
-error[E0425]: unresolved name `bar`
+error[E0425]: unresolved value `bar`
--> $DIR/typo-suggestion.rs:15:26
|
15 | println!("Hello {}", bar);
- | ^^^ unresolved name
+ | ^^^ no resolution found
-error[E0425]: unresolved name `fob`
+error[E0425]: unresolved value `fob`
--> $DIR/typo-suggestion.rs:18:26
|
18 | println!("Hello {}", fob);
lock: Option<&'static str>,
}
-const TEST_REPOS: &'static [Test] = &[Test {
- name: "cargo",
- repo: "https://github.com/rust-lang/cargo",
- sha: "b7be4f2ef2cf743492edc6dfb55d087ed88f2d76",
- lock: None,
- },
- Test {
- name: "iron",
- repo: "https://github.com/iron/iron",
- sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
- lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
- }];
-
+const TEST_REPOS: &'static [Test] = &[
+ Test {
+ name: "cargo",
+ repo: "https://github.com/rust-lang/cargo",
+ sha: "b7be4f2ef2cf743492edc6dfb55d087ed88f2d76",
+ lock: None,
+ },
+ Test {
+ name: "iron",
+ repo: "https://github.com/iron/iron",
+ sha: "16c858ec2901e2992fe5e529780f59fa8ed12903",
+ lock: Some(include_str!("lockfiles/iron-Cargo.lock")),
+ },
+ Test {
+ name: "ripgrep",
+ repo: "https://github.com/BurntSushi/ripgrep",
+ sha: "b65bb37b14655e1a89c7cd19c8b011ef3e312791",
+ lock: None,
+ },
+ Test {
+ name: "tokei",
+ repo: "https://github.com/Aaronepower/tokei",
+ sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928",
+ lock: None,
+ },
+ Test {
+ name: "treeify",
+ repo: "https://github.com/dzamlo/treeify",
+ sha: "999001b223152441198f117a68fb81f57bc086dd",
+ lock: None,
+ },
+ Test {
+ name: "xsv",
+ repo: "https://github.com/BurntSushi/xsv",
+ sha: "5ec4fff4a3f507eda887049469897f02c6fae036",
+ lock: None,
+ },
+];
fn main() {
// One of the projects being tested here is Cargo, and when being tested
authors = ["The Rust Project Developers"]
name = "rustbook"
version = "0.0.0"
+build = false
[[bin]]
name = "rustbook"